选择多个XML子节点作为单独的结果

时间:2014-12-17 11:45:41

标签: sql sql-server xml

我需要从XML文档中选择数据。该文档的结构如下例所示:

<parameters>
    <set>
        <attribId>4711</attribId>
        <attribId>4712</attribId>
        <matnr>000000000001206433</matnr>
        <vkorg>2420</vkorg>
        <spras>NL</spras>
    </set>
    <set>
        <attribId>4750</attribId>
        <matnr>000000000001007885</matnr>
        <matnr>000000000001007886</matnr>
        <vkorg>2420</vkorg>
        <spras>NL</spras>
    </set>
</parameters>

结果集应如下所示

attribId    matnr               vkorg   spras
4711        000000000001206433  2420    NL
4712        000000000001206433  2420    NL
4750        000000000001007885  2420    NL
4750        000000000001007886  2420    NL

正如您所看到的,节点attribId和matnr可能会多次出现。目前我尝试选择以下方式:

SELECT
  c.value('attribId[1]', 'int')            AS attribId,
  c.value('vkorg[1]', 'char(4)')           AS VKORG,
  c.value('spras[1]', 'char(2)')           AS SPRAS,
  c.value('matnr[1]', 'nvarchar(18)')      AS MATNR
FROM @parameters.nodes('/parameters/set')      AS t(c); 

在这个select语句中,变量@parameters包含XML文档。结果显然是:

attribId    matnr               vkorg   spras
4711        000000000001206433  2420    NL
4750        000000000001007885  2420    NL

缺少其他结果行。我如何选择获得第一个描述的结果集?提前谢谢。

2 个答案:

答案 0 :(得分:1)

你可以试试这个:

首先将所有元素选择到单独的表中(我只是使用内联表)然后根据set id将它们连接在一起。在这种情况下,我推断出一个set id,因为它没有在你的xml中指定。

我还假设每组中每列至少有一个值 - 因此我使用内连接

DECLARE @parameters xml = '<parameters>
    <set>
        <attribId>4711</attribId>
        <attribId>4712</attribId>
        <matnr>000000000001206433</matnr>
        <vkorg>2420</vkorg>
        <spras>NL</spras>
    </set>
    <set>
        <attribId>4750</attribId>
        <matnr>000000000001007885</matnr>
        <matnr>000000000001007886</matnr>
        <vkorg>2420</vkorg>
        <spras>NL</spras>
    </set>
</parameters>'

select 
    attribId,
    matnr,
    vkorg,
    spras
FROM (  
        select  
            t.c.value('count(for $a in . return $a/../../*[. << $a])','int') as parentID,
            c.value('.', 'int') AS attribId
        FROM @parameters.nodes('/parameters/set/attribId')      AS t(c)
    ) a
INNER JOIN (
        select  
            t.c.value('count(for $a in . return $a/../../*[. << $a])','int') as parentID,
            c.value('.', 'char(4)') AS vkorg
        FROM @parameters.nodes('/parameters/set/vkorg')      AS t(c)
    ) v ON a.parentID = v.parentID
INNER JOIN (
        select  
            t.c.value('count(for $a in . return $a/../../*[. << $a])','int') as parentID,
            c.value('.', 'char(2)') AS spras
        FROM @parameters.nodes('/parameters/set/spras')      AS t(c)
    ) s ON s.parentID = a.parentID
 INNER JOIN (
     select  
        t.c.value('count(for $a in . return $a/../../*[. << $a])','int') as parentID,
        c.value('.', 'nvarchar(18)') AS matnr
    FROM @parameters.nodes('/parameters/set/matnr')      AS t(c)
 ) m ON m.parentID = a.parentID

如果集合中有id,则可以执行此操作:

DECLARE @parameters xml = '<parameters>
    <set id="1">
        <attribId>4711</attribId>
        <attribId>4712</attribId>
        <matnr>000000000001206433</matnr>
        <vkorg>2420</vkorg>
        <spras>NL</spras>
    </set>
    <set id="2">
        <attribId>4750</attribId>
        <matnr>000000000001007885</matnr>
        <matnr>000000000001007886</matnr>
        <vkorg>2420</vkorg>
        <spras>NL</spras>
    </set>  
</parameters>'


select 
    attribId,
    matnr,
    vkorg,
    spras
FROM (  
        select  
            c.value('./../@id','varchar(200)') as parentID,
            c.value('.', 'int') AS attribId
        FROM @parameters.nodes('/parameters/set/attribId')      AS t(c)
    ) a
INNER JOIN (
        select  
            c.value('./../@id','varchar(200)') as parentID,
            c.value('.', 'char(4)') AS vkorg
        FROM @parameters.nodes('/parameters/set/vkorg')      AS t(c)
    ) v ON a.parentID = v.parentID
INNER JOIN (
        select  
            c.value('./../@id','varchar(200)') as parentID,
            c.value('.', 'char(2)') AS spras
        FROM @parameters.nodes('/parameters/set/spras')      AS t(c)
    ) s ON s.parentID = a.parentID
 INNER JOIN (
     select  
        c.value('./../@id','varchar(200)') as parentID,
        c.value('.', 'nvarchar(18)') AS matnr
    FROM @parameters.nodes('/parameters/set/matnr')      AS t(c)
 ) m ON m.parentID = a.parentID

答案 1 :(得分:1)

这可以为您提供您正在寻找的内容:

DECLARE @xml XML = '<parameters>
    <set>
        <attribId>4711</attribId>
        <attribId>4712</attribId>
        <matnr>000000000001206433</matnr>
        <vkorg>2420</vkorg>
        <spras>NL</spras>
    </set>
    <set>
        <attribId>4750</attribId>
        <matnr>000000000001007885</matnr>
        <matnr>000000000001007886</matnr>
        <vkorg>2420</vkorg>
        <spras>NL</spras>
    </set>
</parameters>'

SELECT
    attribId_node.value('(./text())[1]', 'varchar(50)') AS attribId,
    matnr_node.value('(./text())[1]', 'varchar(50)') AS matnr,
    vkorg_node.value('(./text())[1]', 'varchar(50)') AS vkorg,
    spras_node.value('(./text())[1]', 'varchar(50)') AS spras
FROM @xml.nodes('/parameters/set') AS s (set_node)
CROSS APPLY s.set_node.nodes('./attribId') AS a (attribId_node)
CROSS APPLY s.set_node.nodes('./matnr') AS b (matnr_node)
CROSS APPLY s.set_node.nodes('./vkorg') AS c (vkorg_node)
CROSS APPLY s.set_node.nodes('./spras') AS d (spras_node)