web-dev-qa-db-ja.com

このクロス適用のある派生テーブルはどのように機能しますか?

データウェアハウス用のブリッジテーブルを作成するために、診断コードの文字列を圧縮および圧縮解除する方法に関するコードをいくつか借りました。それはうまくいきます。しかし、私はそれがどのように非コンパクト化を行っているかを理解していません。 ここにSQL Fiddle

create table dimDiagnosisGroup (dxGroupKey int, dxCodeList nvarchar(1024))
insert into dimDiagnosisGroup
values  (1,'042, 070.70, 722.10'),
        (2,'042, 070.70, 780.52, 496, 716.90, 581.9'),
        (3,'042, 070.70, 782.1, V58.69'),
        (4,'042, 070.70, 782.3, V58.69')


 WITH XMLTaggedList AS (
     SELECT dxGroupKey,
        CAST('<I>' + REPLACE(dxCodeList, ', ', '</I><I>') + '</I>' AS XML)
            AS Diagnosis_Code_List
     FROM dimDiagnosisGroup
 )
     SELECT dxGroupKey,
            ExtractedDiagnosisList.X.value('.', 'VARCHAR(MAX)') AS dxCodeList2
          FROM XMLTaggedList
        CROSS APPLY Diagnosis_Code_List.nodes('//I') AS ExtractedDiagnosisList(X)

XMLTaggedListの部分はうまく理解しています。私が理解していないのは、ExtractedDiagnosisList(X)へのクロス適用であり、次にExtractedDiagnosisList.X.valueです。 ( '。'、 'VARCHAR(MAX)')

SelectステートメントでExtractedDiagnosisListにカーソルを合わせると、SSMSはそれが派生テーブルであると表示します。しかし、それは私には機能のように見えます。 Diagnosis_Code.Listが.nodes( '// I')関数を取得する方法を理解していません。最後に、ExtractedDiagnosisList.X.valueセクションは、SQLで私には無関係に見えます。 C#のような言語の構文のように見えます。

6

SQL ServerでのXQuery実装が表示されています。 XQueryは独自のパーサーを使用し、クエリのコンパイル段階で独自の代数化を実行しますが、結果はクエリのDML部分と組み合わされて最適化された後、単一の実行プランに組み合わされます。

SQL Serverは5つの異なる方法をサポートしています。 valueexistquery 、およびnodesは、データにアクセスして変換するために使用されます。最後のmodifyは、XML DMLを使用してデータを変更します。

Value()メソッドはXMLインスタンスからスカラー値を返しますxmlがあるとしましょう: `

declare @X xml =
'<Order OrderId="42" OrderTotal="49.96">
<Customer Id="123"/>
<OrderLineItems>
<OrderLineItem>
<ArticleId>250</ArticleId>
<Quantity>3</Quantity>
<Price>9.99</Price>
</OrderLineItem>
</OrderLineItems>
</Order>’

select @X.value('/Order[1]/Customer[1]/@Id','int')`or
select @X.value('(/Order/Customer/@Id)[1]','int')

最初の注文から最初の顧客のIDを提供します

あなたの特定のケースでは、value( '。')はシュレッドされた要素からのすべての値を私に与えることを意味します(これについては後で説明します)。これで、より簡単に、「移動」しすぎないようにするために、関数nodeを使用できます。 XMLをリレーショナルデータに分解します。パス式で識別されたノードを表す行を含む行セットを返します。

例:

declare @X xml =
'<Order OrderId="42" OrderTotal="49.96">
<Customer Id="123"/>
<OrderLineItems>
<OrderLineItem>
<ArticleId>250</ArticleId>
<Quantity>3</Quantity>
<Price>9.99</Price>
</OrderLineItem>
</OrderLineItems>
</Order>'


select C.t.value('(@Id)[1]','int')
from  @X.nodes('/Order/Customer') as C(t)

テーブルのXML列でnodes()メソッドを使用する場合は、APPLY演算子を使用する必要があります。

例:

declare @X as table (xmlCode varchar(1000))
insert into @X values (
'<Order OrderId="42" OrderTotal="49.96">
<Customer Id="123"/>
<OrderLineItems>
<OrderLineItem>
<ArticleId>250</ArticleId>
<Quantity>3</Quantity>
<Price>9.99</Price>
</OrderLineItem>
</OrderLineItems>
</Order>');

WITH CTE AS(
select CAST(xmlCode as XML) as X from @X
)
select C.t.value('(@Id)[1]','int')
from  CTE
CROSS APPLY X.nodes('/Order/Customer') as C(t)

値とノードの例を使用しました。これらの2つの関数のみをコードに提供したので、それについて詳しく知りたい場合は this にアクセスしてください。

この簡単な例がxml型をクエリする方法のアイデアを与えることを願っています

7
S4V1N

クロス適用は .nodes() XQuery呼び出しと組み合わせて使用​​されています。これは基本的に、XMLTaggedList CTEステートメント内で構築されたXML配列のすべての要素_<I></I>_を取得しています。次に、外側の .value() XQuery呼び出しがその値を抽出してVARCHAR(MAX)にキャストし、各グループ内の各コードのレコードを返します。

クエリを分割すると、ダイジェストが簡単になります。多分あなたもそうでしょう。

_DECLARE @dimDiagnosisGroup TABLE (dxGroupKey int, dxCodeList nvarchar(1024))
insert into @dimDiagnosisGroup
values  (1,'042, 070.70, 722.10'),
        (2,'042, 070.70, 780.52, 496, 716.90, 581.9'),
        (3,'042, 070.70, 782.1, V58.69'),
        (4,'042, 070.70, 782.3, V58.69')

-- Construct the XML arrays, this is what's going on within the CTE
SELECT dxGroupKey,
CAST('<I>' + REPLACE(dxCodeList, ', ', '</I><I>') + '</I>' AS XML)
    AS Diagnosis_Code_List
FROM @dimDiagnosisGroup

-- Extract all elements for each group
 ;WITH XMLTaggedList AS (
     SELECT dxGroupKey,
        CAST('<I>' + REPLACE(dxCodeList, ', ', '</I><I>') + '</I>' AS XML)
            AS Diagnosis_Code_List
     FROM @dimDiagnosisGroup
 )
     SELECT dxGroupKey,
            -- Extract the Value from the <I></I> element and cast it as a VARCHAR(MAX)
            ExtractedDiagnosisList.X.value('.', 'VARCHAR(MAX)') AS dxCodeList2
          FROM XMLTaggedList
        -- Seperate each <I></I> element into it's own row
        CROSS APPLY Diagnosis_Code_List.nodes('//I') AS ExtractedDiagnosisList(X)
_
3
John Eisbrener

John Eisbrenerの回答への補遺

ExtractedDiagnosisList(X)の部分に関しては、その中にスペースがあると、一部の人にとって役立つ場合があります。

ExtractedDiagnosisList (X)

SQL docs から、派生テーブル(および行セット関数、@ variable。function_calls)を使用すると、テーブルエイリアスだけでなく、問題の「テーブル」で返される列の列エイリアス。この場合、1つの列があり、それをXと呼びます。

見る?

[FROM {} [、... n]]
:: =
{

...

| rowset_function [[AS] table_alias]
[(bulk_column_alias [、... n])]

...

| derived_table [[AS] table_alias] [(column_alias [、... n])]

...

| @ variable.function_call(expression [、... n])
[[AS] table_alias] [(column_alias [、... n])]

...

2
RDFozz