7

FORXMLEXPLICITを使用してXMLを生成する1000行のストアドプロシージャを継承しました。私の問題は、それがほとんどの場合機能することです。一部のシナリオでは、次のエラーが発生します。

親タグID2はオープンタグに含まれていません。FOR XML EXPLICITでは、最初に親タグを開く必要があります。結果セットの順序を確認してください。番号:6833重大度:16状態:1

これをトラブルシューティングする方法についてのアイデアが必要です。ネストが失敗している場所を見つける必要があります。親行が発行されていないのに、子行が発行されている可能性があります。さらに悪いことに、この問題はテストシステムでのみ発生し、本番データの一部が欠落している可能性があります。問題は、何千もの行からこれを見つける方法です。

確かに存在しないという1つのワイルドなアイデア:SQL Serverには、行が正しい順序であるかどうかを判断するために使用するアルゴリズムがあります。私の結果セットを(FOR XML EXPLICITなしで)見て、問題がどこにあるかを見つけて、それについて教えてくれるツールがあれば、(ありそうもないとしても)素晴らしいでしょう。

そのようなツールがない場合は、これをデバッグする方法についての提案を歓迎します。XML(動作する場合)は4レベルの深さです!


更新:これまでのすべての回答に感謝します。これは、不適切に編集されたストアドプロシージャの問題のようです。大きなセクションは「/*/」コメントでコメント化されました-コードにすでに「/*/」コメントがある場合はうまく機能しません...答えが確実になったら、もう一度更新します。

4

4 に答える 4

10

考えられる1つの方法は、実際にFOR XML EXPLICIT部分を削除し、SQLステートメントによって生成された結果セットを確認することです。これにより、xmlを生成しているネストが示され、問題が発生する可能性があります。http://msdn.microsoft.com/en-us/library/ms189068.aspxにあるMSDNドキュメントから抜粋した以下の画像を参照して ください。

代替テキスト


編集

サンプル出力を投稿する価値があるかもしれませんが、画像の例では、tag = 3の行のOrder!2!Idがnullの場合、同じエラーが発生します。この列は、事実上、tag=2の親行とtag=3の子行の間の結合です。データが上記のようなものである場合、parent = 2で行を識別し、Order!2!Idがnullである場合、問題を効果的に見つけることができると思います。

または、注文することもできます。この場合、結果セットでTag=2の行の前に発生するParent=2の行を識別するクエリを作成できます。


編集2

CREATE TABLE MyTable(
    Tag int,
    Parent int,
    SomeIdentifier int
)   

INSERT INTO MyTable VALUES (2, 1, 1) -- this row defined before parent
INSERT INTO MyTable VALUES (1, null, 1)
INSERT INTO MyTable VALUES (3, 2, 1)
INSERT INTO MyTable VALUES (3, 2, 1)
INSERT INTO MyTable VALUES (1, null, 2)
INSERT INTO MyTable VALUES (2, 1, 2)
INSERT INTO MyTable VALUES (3, 2, 2)
INSERT INTO MyTable VALUES (3, 2, 2)
INSERT INTO MyTable VALUES (1, null, 3)
INSERT INTO MyTable VALUES (3, 2, 3) -- this is orphaned
INSERT INTO MyTable VALUES (3, 2, 3) -- this is orphaned

;WITH myCte AS(
SELECT   Tag
        ,Parent
        ,SomeIdentifier
        ,ROW_NUMBER() OVER (PARTITION BY SomeIdentifier ORDER BY(SELECT 0)) AS RowOrder
FROM    MyTable   
) SELECT c1.Tag
        ,c1.Parent
        ,c1.SomeIdentifier
FROM myCte c1 
LEFT OUTER JOIN myCte c2 ON c2.SomeIdentifier = c1.SomeIdentifier AND c1.Parent = c2.Tag
WHERE c1.Parent IS NOT NULL     --ignore root rows for now
AND   (c1.RowOrder < c2.RowOrder    --out of order rows
        OR    
       c2.Tag IS NULL)      --orphaned rows
于 2010-12-17T00:56:25.537 に答える
4

FOR XMLを使用する場合、結果セットの順序には、子の前に親xmlノードが必要です(通常、XMLファイルは順序に依存しないでください。これは、XSL変換を使用して実行する必要があります)

興味深い:The Art of XSD(無料の電子ブック)

あなたはおそらくこれをすでに知っているでしょう:XSDを持っているなら、あなたはXSDに対してXMLを検証するためにツールを使うことができます(またはそれをするために約10行のC#を書く):

Visual C#.NETでDTD、XDR、またはXSDを使用してXMLドキュメントを検証する方法

整形式のXMLの例がある場合は、を使用してXSDを生成できますXSD.exe

于 2010-12-17T00:28:50.150 に答える
2

行セット(FOR XML句なし)を一時テーブルにダンプします。これで、このテーブル内で孤立したユーザーを検索できるようになります。

孤立した子が見つからない場合は、順序に問題があることを示している傾向があります(親は行セットにありますが、子の後に表示されます)。しかし、少なくともこの問題の検索スペースは半分になります:-)

于 2010-12-17T08:39:47.493 に答える
2

私はこれらの問題の1つに対する答えを見つけ、私が学んだいくつかの教訓を共有したいと思いました。

ストアドプロシージャの本質を理解し、結果セットをテーブル変数に挿入するように変更しました。レッスン1:テーブル変数で列型が正しいことを確認します-列型をvarcharからintに誤って変更したために発生した問題を追跡するのに何時間も費やしました。これにより、並べ替え順序が変更され、問題が発生しました。

テーブル変数を修正すると、次のような便利なクエリを実行できるようになりました。

SELECT TOP n *
FROM @result
ORDER BY <same order as original query>
FOR XML EXPLICIT

どの行に問題があるかを判断するには、「バイナリ検索」を実行する必要があると思いました。結局のところ、問題は最初の数行にありました。

レベル2のデータは、ルックアップテーブルへの内部結合を含むクエリによって形成されました。これにより、ルックアップ列がマップされない場合は常に行全体が省略されていました。これにより、対応するレベル3および4の行が発行されるのを防ぐことができなかったため、エラーが発生しました。

ルックアップにLEFTJOINを使用すると、問題が解決しました。

于 2010-12-23T17:46:59.280 に答える