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 有点反规范化,因为每对 NSM 节点在一起。

不幸的是,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

SQL Fiddle