65

DATA01我有两个名为和的 SQL Server(运行 SQL Server 2008)DATA02DATA02有一个链接服务器定义LINK,指向DATA01,并设置了合适的用户映射。上面DATA01有一个MyDatabase包含这两个表的数据库:

CREATE TABLE T_A (
    Id int
)

CREATE TABLE T_B (
    Id int,
    Stuff xml
)

当我从 运行此命令时DATA02,我得到按预期返回的数据:

SELECT Id FROM LINK.MyDatabase.dbo.T_A;

但是,当我从 运行此命令时DATA02,出现错误:

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

错误是

分布式查询不支持 XML 数据类型。远程对象 'DATA02.MyDatabase.dbo.T_B' 具有 xml 列。

奇怪的是,这个命令:

SELECT Id FROM LINK.MyDatabase.dbo.T_B;

也给出了同样的错误,即使我没有SELECTing xml 列!这是怎么回事?

4

3 回答 3

105

这是 SQL Server 中的一个缺陷。表上仅仅存在一个 xml 列会阻止它参与分布式查询(例如,通过链接服务器连接进行查询)。此“已退休”文档中提到了这一点。当前版本的文档中似乎没有提到这一点。

Microsoft Connect 上曾经有相关的错误报告,但现在已经“退休”,有利于 Azure 反馈论坛。此反馈项已关闭,并带有“请直接从产品文档提交反馈”的说明,如果产品文档中确实提到了这一点,那就没问题了。此其他反馈项包括从 Connect 迁移的评论,并且状态为“未计划”。

曾经存在的 Connect 错误报告之一提供了两种解决方法:

  1. 在远程服务器上创建没有 XML 列的 [a] 视图并进行查询。

    在您的示例中,这将涉及添加一个MyDatabase 如下所示的视图:

    CREATE VIEW V_T_B AS SELECT Id FROM T_B;
    

    然后,您可以通过链接查询此视图以获取Id 数据。请注意,类似

    SELECT Id FROM ( SELECT Id FROM T_B ) T_B;
    

    不起作用

  2. 在表单中使用传递查询

    SELECT * from OPENQUERY (... )
    

    这种方法的优点是不需要对源数据库进行任何更改;缺点是不再可能对本地和链接数据使用标准的四部分命名。查询看起来像

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

    请注意,如果您确实需要xml 数据,则需要此方法(以及与非 xml 数据类型之间的转换):

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

请注意,该错误最初是在 SQL Server 2005 中报告的,并且在 SQL Server 2017 中仍未修复。我还无法检查 SQL Server 2019。

于 2013-01-21T15:36:26.840 回答
11

尝试这个:

  • 使用 xml 转换为 nvarchar(max) 在源端创建一个视图:

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

  • 您可以使用 cast to xml 在目标端选择它

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

该解决方案在 2008R2 中适用于我。

于 2013-07-25T07:40:15.817 回答
8

我找到了另一种方法:

  1. 创建一个Linked Serveron DATA01DATA02甚至是第三个服务器(可能是本地的)。
  2. 使用 执行您的查询EXEC [linked_server].[sp_executesql]

为什么我更喜欢这种方法而不是创建视图或使用OPENQUERY

  1. 此方法不需要对链接服务器具有任何权限(您不需要创建视图)。
  2. sp_executesql您可以使用语法将参数传递给您的查询(在此处查找有关 sp_sqlexecute 的更多信息)。因为OPENQUERY你必须传递一个STRINGor TEXT_LEX,所以这意味着所有的值都必须直接输入到这个函数中。

这是示例:

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
于 2018-11-21T20:57:37.937 回答