Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get the error "Xml data type is not supported in distributed queries" when querying a linked server for non-xml data?

I have two SQL Servers (running SQL Server 2008) named DATA01 and DATA02. DATA02 has a linked server definition LINK, that points at DATA01, with suitable user mapping set up. On DATA01 there is a database MyDatabase containing these two tables:

CREATE TABLE T_A (
    Id int
)

CREATE TABLE T_B (
    Id int,
    Stuff xml
)

When I run this command from DATA02, I get data returned as expected:

SELECT Id FROM LINK.MyDatabase.dbo.T_A;

However, when I run this command from DATA02, I get an error:

SELECT Id, Stuff FROM LINK.MyDatabase.dbo.T_B;

The error is

Xml data type is not supported in distributed queries. Remote object 'DATA02.MyDatabase.dbo.T_B' has xml column(s).

And strangely, this command:

SELECT Id FROM LINK.MyDatabase.dbo.T_B;

also gives the same error, even though I'm not SELECTing the xml column! What's going on?

like image 644
AakashM Avatar asked Jan 21 '13 15:01

AakashM


People also ask

Which datatype is not supported by XML?

Xml data type is not supported in distributed queries.

How do I get data from XML format in SQL Server?

SQL Server lets you retrieve data as XML by supporting the FOR XML clause, which can be included as part of your query. You can use the FOR XML clause in the main (outer) query as well as in subqueries. The clause supports numerous options that let you define the format of the XML data.

What is XML data type in SQL Server?

The xml data type is a built-in data type in SQL Server and is somewhat similar to other built-in types such as int and varchar. As with other built-in types, you can use the xml data type as a column type when you create a table as a variable type, a parameter type, a function-return type, or in CAST and CONVERT.

How is the support for XML integrated into SQL Server?

Support for XML is integrated into all the components in SQL Server in the following ways: The xml data type. XML values can be stored natively in an xml data type column that can be typed according to a collection of XML schemas, or left untyped. You can index the XML column.


3 Answers

This is a deficiency within SQL Server. The mere existence of an xml column on the table prevents it from participating in distributed queries (eg being queried through a linked server connection). This is mentioned in this 'retired' documentation. There doesn't appear to be any mention of this in the current version's documentation.

There used to be relevant bug reports on Microsoft Connect, but that's now been 'retired' in favour of the Azure feedback forums. This feedback item is Closed with an instruction to "Please submit feedback directly from the product documentation", which would be fine if the product documentation actually mentioned this. This other feedback item includes commentary migrated from Connect, and has the status 'Unplanned'.

One of the Connect bug reports that used to exist gave two workarounds:

  1. Create [a] view without the XML column(s) on remote server and query that.

    In your example, this would involve adding a view to MyDatabase that looks like this:

    CREATE VIEW V_T_B AS SELECT Id FROM T_B;
    

    You could then query this view through the link to get the Id data. Note that something like

    SELECT Id FROM ( SELECT Id FROM T_B ) T_B;
    

    doesn't work.

  2. Use a pass-through query in the form

    SELECT * from OPENQUERY (... )
    

    This method has the advantage of not requiring any change to the source database; the downside is that it is no longer possible to use standard four-part naming for both local and linked data. The query would look like

     SELECT Id FROM OPENQUERY(DATA02, 'SELECT Id FROM T_B') T_B;
    

    Note that if you actually do want the xml data, this method (along with casting to and from a non-xml datatype) will be required :

     SELECT Id, CAST(Stuff AS XML) Stuff 
     FROM OPENQUERY(DATA02, 'SELECT Id, CAST(Stuff AS nvarchar(max)) Stuff 
                             FROM T_B') T_B;
    

Note that the bug was first reported in SQL Server 2005, and remains unfixed in SQL Server 2017. I haven't yet been able to check SQL Server 2019.

like image 178
AakashM Avatar answered Oct 24 '22 03:10

AakashM


Try this:

  • Create a view on the source side with xml cast to nvarchar(max):

CREATE VIEW vXMLTest AS SELECT cast(Stuff as nvarchar(max)) as STUFF FROM T_B

  • You can select it on the destination side with cast to xml

SELECT Cast(Stuff as XML) as Stuff FROM OPENQUERY(DATA02, 'SELECT Stuff FROM vXMLTest')

This solution works for me in 2008R2.

like image 29
Csaba Molnár Avatar answered Oct 24 '22 02:10

Csaba Molnár


I found another way of doing this:

  1. Create a Linked Server on DATA01, DATA02 or even some third server (could be local).
  2. Execute your query using EXEC [linked_server].[sp_executesql].

Why I prefer this method over creating Views or using OPENQUERY?

  1. This method does not require to have any permissions on the Linked Server (you don't need to create Views).
  2. You could pass a parameters to your query using the sp_executesql syntax (find more information about sp_sqlexecute here). For OPENQUERY you must pass a STRING or TEXT_LEX, witch means that all the values must be typed right into this function.

Here is the example:

DECLARE @UserID UNIQUEIDENTIFIER = ''

DECLARE @SearchForUserParams NVARCHAR(MAX) = N'@UserID UNIQUEIDENTIFIER';  
DECLARE @SearchForUserQuery NVARCHAR(MAX) = 
N'SELECT
    UserID,
    Username,
    Email,
    CONVERT(NVARCHAR(MAX), UserDataXml) AS UserDataXml
FROM User
WHERE UserID = @UserID'

EXEC [linked_server].[dbo].[sp_executesql] 
    @SearchForUserQuery,
    @SearchForUserParams,
    @UserID = @UserID
like image 9
semptra Avatar answered Oct 24 '22 03:10

semptra