SQL Server 2005 の XQuery を使用して、特定の属性値を持つノード、またはその属性が欠落しているノードをすべて選択します
-
01-07-2019 - |
質問
アップデート:より完全な例を挙げます。
提供された最初の 2 つの解決策は、私が言いたかったこととぴったり一致していました。 ない すること。場所が分からないので、ドキュメントツリー全体を見ることができる必要があります。したがって、コンテキストとして /Books/ を指定した次のような解決策は機能しません。
SELECT x.query('.') FROM @xml.nodes('/Books/*[not(@ID) or @ID = 5]') x1(x)
元の質問とより良い例:
SQL Server 2005 の XQuery 実装を使用すると、XML ドキュメント内のすべてのノードを 1 回だけ選択し、元の構造を維持する必要があります。ただし、ノードに特定の属性が欠落している場合、またはその属性に特定の値 (パラメーターによって渡される) がある場合に限ります。また、クエリは、事前定義された深さで選択するのではなく、XML ドキュメント全体 (子孫または自己軸) に対して機能する必要があります。
つまり、個々のノードとその祖先のすべてが属性を欠いている場合、または単一の特定の値を持つ属性を持つ場合にのみ、個々のノードが結果のドキュメントに表示されます。
例えば:
これが XML の場合:
DECLARE @Xml XML
SET @Xml =
N'
<Library>
<Novels>
<Novel category="1">Novel1</Novel>
<Novel category="2">Novel2</Novel>
<Novel>Novel3</Novel>
<Novel category="4">Novel4</Novel>
</Novels>
<Encyclopedias>
<Encyclopedia>
<Volume>A-F</Volume>
<Volume category="2">G-L</Volume>
<Volume category="3">M-S</Volume>
<Volume category="4">T-Z</Volume>
</Encyclopedia>
</Encyclopedias>
<Dictionaries category="1">
<Dictionary>Webster</Dictionary>
<Dictionary>Oxford</Dictionary>
</Dictionaries>
</Library>
'
カテゴリのパラメータを 1 にすると、次のようになります。
<Library>
<Novels>
<Novel category="1">Novel1</Novel>
<Novel>Novel3</Novel>
</Novels>
<Encyclopedias>
<Encyclopedia>
<Volume>A-F</Volume>
</Encyclopedia>
</Encyclopedias>
<Dictionaries category="1">
<Dictionary>Webster</Dictionary>
<Dictionary>Oxford</Dictionary>
</Dictionaries>
</Library>
カテゴリのパラメータを 2 にすると、次のようになります。
<Library>
<Novels>
<Novel category="2">Novel2</Novel>
<Novel>Novel3</Novel>
</Novels>
<Encyclopedias>
<Encyclopedia>
<Volume>A-F</Volume>
<Volume category="2">G-L</Volume>
</Encyclopedia>
</Encyclopedias>
</Library>
XSLT がこの仕事に最適であることはわかっていますが、それは選択肢ではありません。これはすべて SQL Server 2005 で実現する必要があります。完全に T-SQL で実行できる限り、XQuery を使用しない実装でも問題ありません。
解決
あなたの例からは、実際に何を達成しようとしているのかはわかりません。条件を満たすノードを除いてすべてのノードを取り除いた新しい XML を返しますか?「はい」の場合、これは XSLT 変換のジョブのようですが、MSSQL 2005 には組み込まれていないと思います (UDF として追加できます: http://www.topxml.com/rbnews/SQLXML/re-23872_Performing-XSLT-Transforms-on-XML-Data-Stored-in-SQL-Server-2005.aspx).
ノードのリストを返すだけの場合は、次の式を使用できます。
//Book[not(@ID) or @ID = 5]
しかし、それは必要なものではないという印象を受けます。より明確な例を提供していただけると助かります。
編集:この例は確かにより明確です。私が見つけた最高のものはこれです:
SET @Xml.modify('delete(//*[@category!=1])')
SELECT @Xml
目的は、XML から不要なノードをすべて削除して、元の構造と必要なノードを残すことです。あなたの 2 つの例でテストしたところ、望ましい結果が得られました。
しかし 修正する いくつかの制限があります。select ステートメントでは使用できないようです。データを適切に変更する必要があります。このようなデータを選択で返す必要がある場合は、元のデータをコピーしてそのテーブルを更新する一時テーブルを使用できます。このようなもの:
INSERT INTO #temp VALUES(@Xml)
UPDATE #temp SET data.modify('delete(//*[@category!=2])')
それが役立つことを願っています。
他のヒント
質問があまり明確ではありませんが、これがあなたが探しているものですか?
DECLARE @Xml AS XML
SET @Xml =
N'
<Books>
<Book ID="1">Book1</Book>
<Book ID="2">Book2</Book>
<Book ID="3">Book3</Book>
<Book>Book4</Book>
<Book ID="5">Book5</Book>
<Book ID="6">Book6</Book>
<Book>Book7</Book>
<Book ID="8">Book8</Book>
</Books>
'
DECLARE @BookID AS INT
SET @BookID = 5
DECLARE @Result AS XML
SET @result = (SELECT @xml.query('//Book[not(@ID) or @ID = sql:variable("@BookID")]'))
SELECT @result