使用逗号分隔的条目将XML解析为SQL Server中的表

时间:2017-12-06 17:56:13

标签: sql-server xml

我有一个类似这样的XML文件

    declare @X XML
     Set @X  ='<A> 
        <B> 
        <C>161</C> 
        <D>190</D> 
        <E>43 ,44 ,48 ,49</E> 
        </B>
    <B> 
    <C>162</C> 
    <D>190</D> 
    <E>100</E> 
    </B>
    </A>
'

我想把它解析成表格:

    C         D       E
    161      190     43
    161      190     48
    161      190     49
    162      190     100

我尝试使用

select  
    x.r.value('(A)[1]', 'int') as C,
    x.r.value('(D)[1]', 'int') as D,
    x.r.value('(E)[1]', 'varchar(max)') as E
from    
    @X.nodes('/A/B') as x(r)

DECLARE @xml as xml, @str as varchar(100), @delimiter as varchar(10)

SET @str = '43,48,49'
SET @delimiter = ','
SET @xml = cast(('<X>'+replace(@str,@delimiter ,'</X><X>')+'</X>') as xml)
        SELECT T.N.value('.', 'int') as value FROM @xml.nodes('X') as T(N)

用于将逗号分隔的列E分隔到表中。

但我无法在一个查询中将这两者结合起来,即将其解析为表

2 个答案:

答案 0 :(得分:2)

下次你应该真的避免&#34;变色龙&#34;的问题。特别是当对初始问题的更改使正确答案无效时,这被认为是不礼貌的......

你做了什么:通过接受最有用的答案并开始一个新问题来关闭这个问题。

然而,这是一种有效的方法:

DECLARE @X XML =
N'<A>
  <B>
    <C>161</C>
    <D>190</D>
    <E>43 ,44 ,48 ,49</E>
  </B>
  <B>
    <C>162</C>
    <D>190</D>
    <E>100</E>
  </B>
</A>';

WITH ReturnYourListAsXml AS
(
    SELECT CAST(N'<x>' + REPLACE(B.value(N'(E/text())[1]',N'nvarchar(max)'),',','</x><x>') + '</x>' AS XML) AS E_As_Xml
          ,B.value(N'(C/text())[1]',N'int') AS C
          ,B.value(N'(D/text())[1]',N'int') AS D
          ,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS B_Nr 
    FROM @x.nodes(N'/A/B') AS AllNodes(B)
)
SELECT cte.B_Nr
      ,cte.C
      ,cte.D
      ,YourList.Member.value(N'text()[1]',N'int') AS E
FROM ReturnYourListAsXml AS cte
CROSS APPLY E_As_Xml.nodes(N'/x') AS YourList(Member);

答案 1 :(得分:1)

我修改了我的原始答案,使用您修改过的问题,其中您有多个从属[B]节点。我也冒昧地修改数据,以便结果显而易见(所有&#34; 1&#34; s在一起等)。我喜欢Shnugo的另一个答案,XML分裂字符串版本。我有一段时间没有看到它,但我觉得它更干净,所以我用它。

DECLARE @builder AS TABLE
  (
       [C]   [INT]
       , [D] [INT]
       , [E] [XML]
  );
DECLARE @X XML ='<A> 
    <B> 
        <C>161</C> 
        <D>191</D> 
        <E>41 ,51 ,61 ,71</E> 
    </B>
    <B> 
        <C>162</C> 
        <D>192</D> 
        <E>102</E> 
    </B>
    <B> 
        <C>163</C> 
        <D>193</D> 
        <E>43, 53, 63</E> 
    </B>
</A>';

WITH [row_builder]
     AS (SELECT t.c.query(N'.') AS [b_row]
         FROM   @X.nodes(N'/A/B') AS [t]([c]))
   , [shredder]
     AS (SELECT [b_row].value(N'(./B/C/text())[1]', N'[INT]')             AS [C]
                , [b_row].value(N'(./B/D/text())[1]', N'[INT]')           AS [D]
                , [b_row].value(N'(./B/E/text())[1]', N'[NVARCHAR](MAX)') AS [E]
         FROM   [row_builder])
   , [splitter]
     AS (SELECT [C]
                , [D]
                , cast(( '<E>' + replace([E], N',', '</E><E>') + '</E>' ) AS XML) AS [E]
         FROM   [shredder])
SELECT [C]
       , [D]
       , [column].query(N'.').value(N'(/E/text())[1]', N'[INT]') AS [E]
FROM   [splitter] AS [entry]
       CROSS APPLY [E].[nodes]('/*') AS [table] ( [column] )
ORDER  BY [C]
          , [D]
          , [E];