J'ai deux serveurs SQL (exécutant SQL Server 2008) nommés DATA01
et DATA02
. DATA02
a une définition de serveur lié LINK
, qui pointe sur DATA01
, avec le mappage utilisateur approprié configuré. Sur DATA01
il y a une base de données MyDatabase
contenant ces deux tables:
CREATE TABLE T_A (
Id int
)
CREATE TABLE T_B (
Id int,
Stuff xml
)
Lorsque j'exécute cette commande à partir de DATA02
, les données sont renvoyées comme prévu:
SELECT Id FROM LINK.MyDatabase.dbo.T_A;
Cependant, lorsque j'exécute cette commande à partir de DATA02
, j'obtiens une erreur:
SELECT Id, Stuff FROM LINK.MyDatabase.dbo.T_B;
L'erreur est
Le type de données XML n'est pas pris en charge dans les requêtes distribuées. L'objet distant 'DATA02.MyDatabase.dbo.T_B' possède une ou plusieurs colonnes xml.
Et étrangement, cette commande:
SELECT Id FROM LINK.MyDatabase.dbo.T_B;
donne également la même erreur, même si je ne suis pas SELECT
ing la colonne xml! Que se passe-t-il?
Ceci est une lacune dans SQL Server. La simple existence d'une colonne xml sur la table l'empêche de participer aux requêtes distribuées (par exemple, être interrogé via une connexion de serveur lié). Ceci est mentionné dans la documentation , mais pas de manière particulièrement visible. Vous pouvez voir le rapport de bug principal ici , et un rapport similaire ici . Ce dernier donne deux solutions de contournement:
Créez une vue [sans] colonne (s) XML sur le serveur distant et interrogez-la.
Dans votre exemple, cela impliquerait d'ajouter une vue à MyDatabase
qui ressemble à ceci:
CREATE VIEW V_T_B AS SELECT Id FROM T_B;
Vous pouvez ensuite interroger cette vue via le lien pour obtenir les données Id
. Notez que quelque chose comme
SELECT Id FROM ( SELECT Id FROM T_B ) T_B;
ne fonctionne pas .
Utilisez une requête directe dans le formulaire
SELECT * from OPENQUERY (... )
Cette méthode présente l'avantage de ne nécessiter aucune modification de la base de données source; L'inconvénient est qu'il n'est plus possible d'utiliser le nommage standard en quatre parties pour les données locales et liées. La requête ressemblerait à
SELECT Id FROM OPENQUERY(DATA02, 'SELECT Id FROM T_B') T_B;
Notez que si voulez voulez les données xml, cette méthode (ainsi que la conversion vers et depuis un type de données non xml) sera requise :
SELECT Id, CAST(Stuff AS XML) Stuff
FROM OPENQUERY(DATA02, 'SELECT Id, CAST(Stuff AS nvarchar(max)) Stuff
FROM T_B') T_B;
Notez que le bogue a été signalé pour la première fois dans SQL Server 2005 et qu'il n'est pas corrigé dans SQL Server 2014.
Essaye ça:
CREATE VIEW vXMLTestASSELECT cast (Stuff as nvarchar (max)) as STUFF FROM T_B
SELECT Cast (Stuff as XML) en tant que Stuff FROM OPENQUERY (DATA02, 'SELECT Stuff FROM vXMLTest')
Cette solution fonctionne pour moi en 2008R2.
J'ai trouvé un autre moyen de le faire:
Linked Server
sur DATA01
, DATA02
ou même un troisième serveur (qui pourrait être local).EXEC [linked_server].[sp_sqlexecute]
.Pourquoi je préfère cette méthode à la création de vues ou à l'utilisation de OPENQUERY
?
sp_sqlexecute
( pour plus d'informations sur sp_sqlexecute ici ). Pour OPENQUERY
, vous devez passer STRING
ou TEXT_Lex
, ce qui signifie que toutes les valeurs doivent être saisies directement dans cette fonction.Voici l'exemple:
DECLARE @UserID UNIQUEIDENTIFIER = ''
DECLARE @SearchForUserParams NVARCHAR(MAX) = N'@UserID UNIQUEIDENTIFIER';
DECLARE @SearchForUserQuery NVARCHAR(MAX) =
N'SELECT
UserID,
Username,
Email,
CONCART(NVARCHAR(MAX), UserDataXml) AS UserDataXml
FROM User
WHERE UserID = @UserID
'
EXEC [linked_server].[dbo].[sp_executesql]
@SearchForUserQuery,
@SearchForUserParams,
@UserID = @UserID