T-SQL XML 至 Table
T-SQL XML to Table
大家好:)
这是我的问题
我有一个 xml 看起来像这样
DECLARE @xml xml =
'<DT>
<S>534</S>
<NS>238</NS>
<M>2</M>
<NS>239</NS>
<M>1</M>
<NS>240</NS>
<M>1</M>
</DT>';
这是我正在使用的查询
SELECT
A.B.value('(.)[1]', 'nvarchar(100)') AS S,
C.D.value('(.)[1]', 'nvarchar(100)') AS NS,
E.F.value('(.)[1]', 'nvarchar(100)') AS BN
FROM @xml.nodes('/DT') AS X(Y)
OUTER APPLY X.Y.nodes('S') AS A(B)
OUTER APPLY X.Y.nodes('NS') AS C(D)
OUTER APPLY X.Y.nodes('M') AS E(F);
我得到这个结果:
S NS M
534 238 2
534 238 1
534 238 1
534 239 2
534 239 1
534 239 1
534 240 2
534 240 1
534 240 1
但我希望这个:
S NS M
534 238 2
534 239 1
534 240 1
我做错了什么,你能帮我解决这个问题吗?
非常感谢:)
编辑
xml 还有一些条目:
DECLARE @xml xml =
'<DT>
<S>534</S>
<AB>2011</AB>
<NS>238</NS>
<M>2</M>
<NS>239</NS>
<M>1</M>
<NS>240</NS>
<M>1</M>
</DT>
<DT>
<S>535</S>
<AB>2000</AB>
<NS>135</NS>
<M>2</M>
<NS>140</NS>
<M>2</M>
</DT>
<DT>
<S>536</S>
<NS>005</NS>
<M>2</M>
</DT>
<DT>
<S>113</S>
<AB>2006</AB>
<NS>075</NS>
<M>2</M>
<NS>077</NS>
<M>2</M>
<NS>080</NS>
<M>2</M>
</DT>';
输出应该是
S AB NS BN
534 2011 238 2
534 2011 239 1
534 2011 240 1
535 2000 135 2
535 2000 140 2
536 NULL 005 2
113 2006 075 2
113 2006 077 2
113 2006 080 2
如您所见,还有一栏并不总是被填满
这个 XML 有点反规范化,因为每对 NS
和 M
节点在一起。
不幸的是,SQL 服务器不支持 following::
轴,这会使这变得更简单,所以我们需要用 >>
来破解它(is-following?)谓词。
SELECT
X1.DT.value('(S/text())[1]', 'nvarchar(100)') AS S,
X1.DT.value('(AB/text())[1]', 'nvarchar(100)') AS AB,
X2.NS.value('text()[1]', 'nvarchar(100)') AS NS,
X2.NS.value('(let $this := . return parent::DT/M[. >> $this]/text())[1]', 'nvarchar(100)') AS M
FROM @xml.nodes('/DT') X1(DT)
CROSS APPLY X1.DT.nodes('NS') AS X2(NS);
其工作方式是我们首先切碎 DT
个节点。
然后我们进一步切碎 NS
个节点。
那么M
是这样计算的:
(let $this := .
将 $this 变量设置为当前 NS
节点
return parent::DT/M
return 该节点父节点的第一个 M
节点,即...
[. >> $this]
... 位于 $this 之后
This assumes there is only one S
node
大家好:)
这是我的问题 我有一个 xml 看起来像这样
DECLARE @xml xml =
'<DT>
<S>534</S>
<NS>238</NS>
<M>2</M>
<NS>239</NS>
<M>1</M>
<NS>240</NS>
<M>1</M>
</DT>';
这是我正在使用的查询
SELECT
A.B.value('(.)[1]', 'nvarchar(100)') AS S,
C.D.value('(.)[1]', 'nvarchar(100)') AS NS,
E.F.value('(.)[1]', 'nvarchar(100)') AS BN
FROM @xml.nodes('/DT') AS X(Y)
OUTER APPLY X.Y.nodes('S') AS A(B)
OUTER APPLY X.Y.nodes('NS') AS C(D)
OUTER APPLY X.Y.nodes('M') AS E(F);
我得到这个结果:
S NS M
534 238 2
534 238 1
534 238 1
534 239 2
534 239 1
534 239 1
534 240 2
534 240 1
534 240 1
但我希望这个:
S NS M
534 238 2
534 239 1
534 240 1
我做错了什么,你能帮我解决这个问题吗?
非常感谢:)
编辑
xml 还有一些条目:
DECLARE @xml xml =
'<DT>
<S>534</S>
<AB>2011</AB>
<NS>238</NS>
<M>2</M>
<NS>239</NS>
<M>1</M>
<NS>240</NS>
<M>1</M>
</DT>
<DT>
<S>535</S>
<AB>2000</AB>
<NS>135</NS>
<M>2</M>
<NS>140</NS>
<M>2</M>
</DT>
<DT>
<S>536</S>
<NS>005</NS>
<M>2</M>
</DT>
<DT>
<S>113</S>
<AB>2006</AB>
<NS>075</NS>
<M>2</M>
<NS>077</NS>
<M>2</M>
<NS>080</NS>
<M>2</M>
</DT>';
输出应该是
S AB NS BN
534 2011 238 2
534 2011 239 1
534 2011 240 1
535 2000 135 2
535 2000 140 2
536 NULL 005 2
113 2006 075 2
113 2006 077 2
113 2006 080 2
如您所见,还有一栏并不总是被填满
这个 XML 有点反规范化,因为每对 NS
和 M
节点在一起。
不幸的是,SQL 服务器不支持 following::
轴,这会使这变得更简单,所以我们需要用 >>
来破解它(is-following?)谓词。
SELECT
X1.DT.value('(S/text())[1]', 'nvarchar(100)') AS S,
X1.DT.value('(AB/text())[1]', 'nvarchar(100)') AS AB,
X2.NS.value('text()[1]', 'nvarchar(100)') AS NS,
X2.NS.value('(let $this := . return parent::DT/M[. >> $this]/text())[1]', 'nvarchar(100)') AS M
FROM @xml.nodes('/DT') X1(DT)
CROSS APPLY X1.DT.nodes('NS') AS X2(NS);
其工作方式是我们首先切碎 DT
个节点。
然后我们进一步切碎 NS
个节点。
那么M
是这样计算的:
(let $this := .
将 $this 变量设置为当前NS
节点return parent::DT/M
return 该节点父节点的第一个M
节点,即...[. >> $this]
... 位于 $this 之后
This assumes there is only one
S
node