В таких случаях я предпочитаю использовать CROSS APPLY
для вычисления подсчет на лету в качестве производного набора и использовать sql:column()
для чтения связанных с позицией узлов через предикат позиции .
declare @xml xml =
N'<module mod-id="333">
<title>NNN NNNNN NNNNN</title>
<data-code>
<code-id>333-004</code-id>
<description>XXX XXX XXXXXXXX XXX X XXXXXXXXXXXXXXXX</description>
<applic>
<p32>
<condition cond-id="o-000008888">
<ctext> NNN NNNNNNNNN NN NNNNN NNNNNNNNN NN</ctext>
</condition>
<m234 domicile="all" ver-start="4.40" target-ver="4.40" vocation="all">
<value>
<price-container pwdb-id="p-000121212">267</price-container>
<weight-container pwdb-id="w-000676767">0/40</weight-container>
</value>
</m234>
</p32>
</applic>
</data-code>
<data-code>
<code-id>333-005</code-id>
<description>NNNNNNNNNNNNN NNNNNNNNNN NNNNN N NNNN N NNN NNNNNNNN</description>
<applic>
<p32>
<condition cond-id="o-000002222">
<ctext> NNNNNN NNNNN XXXX NNNN XXXX NNNNNNNN XXXXXXXX </ctext>
</condition>
<m234 domicile="all" ver-start="4.40" target-ver="4.40" vocation="all">
<value>
<price-container pwdb-id="p-000123456">N/C</price-container>
<weight-container pwdb-id="w-000234567">0/0</weight-container>
</value>
</m234>
<condition cond-id="o-000033333">
<ctext> Price with DC 622-005 , DC 622-197, , and DC 622-292 </ctext>
</condition>
<m234 domicile="all" ver-start="4.80" target-ver="4.80" vocation="all">
<value>
<price-container pwdb-id="p-000456789">99999</price-container>
<weight-container pwdb-id="w-000789012">0/0</weight-container>
</value>
</m234>
</p32>
</applic>
</data-code>
</module>';
- запрос
SELECT A.dc.value('(code-id/text())[1]','nvarchar(100)') AS data_code
,A.dc.value('(applic/p32/m234[sql:column("Nmbr")]/value/price-container/@pwdb-id)[1]','nvarchar(100)') AS pwdb_id
,A.dc.value('(applic/p32/m234[sql:column("Nmbr")]/value/price-container/text())[1]','nvarchar(100)') AS [text]
,A.dc.value('(applic/p32/condition[sql:column("Nmbr")]/@cond-id)[1]','nvarchar(100)') AS cond_id
FROM @xml.nodes('/module/data-code') A(dc)
CROSS APPLY(SELECT TOP(A.dc.value('count(applic/p32/condition)','int')) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) FROM master..spt_values) B(Nmbr);
Результат
data_code pwdb_id text cond_id
333-004 p-000121212 267 o-000008888
333-005 p-000123456 N/C o-000002222
333-005 p-000456789 99999 o-000033333
Идея вкратце:
Мы используем .nodes()
, чтобы получить повторяющиеся <data-code>
узлы.
Теперь мы используем трюк с CROSS APPLY
: это вернет список от 1 до n в качестве производного набора, где n - это число <condition>
узлов.
Как видите, я могу использовать числа (возвращаемые APPLY
) в sql:column("Nmbr")
.Это выберет condition[1]
вместе с m234[1]
и condition[2]
вместе с m234[2]
и т. Д.
Любое использование обратной навигации ../
и предложенное <<
имеют тенденцию быть очень медленными...