web-dev-qa-db-ja.com

非XMLデータのリンクサーバーをクエリするときに、エラー「Xmlデータ型は分散クエリでサポートされていません」が表示されるのはなぜですか?

DATA01DATA02という名前の2つのSQL Server(SQL Server 2008を実行)があります。 DATA02には、適切なユーザーマッピングが設定されたDATA01を指すリンクサーバー定義LINKがあります。 DATA01には、これらの2つのテーブルを含むデータベース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;

また、同じエラーが発生しますXML列をSELECTingしていないのに!何が起きているのですか?

54
AakashM

これは、SQL Server内の欠陥です。テーブル上のxml列の単なるexistenceにより、分散クエリに参加できなくなります(リンクサーバー接続を介したクエリなど)。これは ドキュメントで言及されています ですが、特に顕著ではありません。 メインの接続バグレポートはこちら 、および 同様のレポートはこちら をご覧ください。後者には2つの回避策があります。

  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 (... )
    

    この方法には、ソースデータベースを変更する必要がないという利点があります。欠点は、ローカルデータとリンクデータの両方に標準の4部構成の命名規則を使用できなくなったことです。クエリは次のようになります

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

    実際にdoがxmlデータを必要とする場合、このメソッドは(非xmlデータ型との間のキャストとともに)required

    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 2014では修正されていないことに注意してください。

91
AakashM

これを試して:

  • Xmlをnvarchar(max)にキャストして、ソース側にビューを作成します。

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

  • Xmlへのキャストで宛先側で選択できます

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

このソリューションは2008R2で機能します。

10
Csaba Molnár

私はこれを行う別の方法を見つけました:

  1. Linked ServerDATA01、または3番目のサーバー(ローカルの場合もある)にDATA02を作成します。
  2. EXEC [linked_server].[sp_sqlexecute]を使用してクエリを実行します。

ビューの作成やOPENQUERYの使用よりもこの方法を好むのはなぜですか?

  1. この方法では、リンクサーバーに対するアクセス許可は必要ありません(ビューを作成する必要はありません)。
  2. sp_sqlexecute構文を使用してクエリにパラメーターを渡すことができます( sp_sqlexecuteの詳細はこちら )。 OPENQUERYの場合、STRINGまたはTEXT_Lexを渡す必要があります。witchは、すべての値をこの関数に直接入力する必要があることを意味します。

以下に例を示します。

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
2
semptra