从SQL Server中的XML列中提取所有属性值

时间:2018-11-27 17:06:05

标签: sql-server xml tsql

我正在尝试从下面的XML中以表格格式提取值。

它最初存储为十六进制,但已成功转换,现在需要以表格格式从中提取所有值。

例如一个ROW

   BID    2 

来自

    <ns2:e k="BID">
            <ns2:l v="2"/>
    </ns2:e>

以此类推。

    <ns2:pay xmlns:ns2="http://someurl.com/">
                <ns2:e k="BID">
                    <ns2:l v="2"/>
                </ns2:e>
                <ns2:e k="PMD">
                    <ns2:l v="1"/>
                </ns2:e>
                <ns2:e k="GPTA5">
                    <ns2:s v=""/>
                </ns2:e>
                <ns2:e k="GPTA4">
                    <ns2:s v=""/>
                </ns2:e>
                <ns2:e k="GPTA3">
                    <ns2:s v="572"/>
                </ns2:e>
                <ns2:e k="GPTA1">
                    <ns2:s v="Sweet &amp; Sour Sauce"/>
                </ns2:e>
                <ns2:e k="PFID">
                    <ns2:l v="1"/>
                </ns2:e>
                <ns2:e k="EAN">
                    <ns2:s v="010000"/>
                </ns2:e>
                <ns2:e k="PT">
                    <ns2:s v="1"/>
                </ns2:eBID>
                <ns2:e k="TXID1">
                    <ns2:l v="0"/>
                </ns2:e>
                <ns2:e k="PMN">
                    <ns2:l v="1"/>
                </ns2:e>
                <ns2:e k="DID">
                    <ns2:l v="1"/>
                </ns2:e>
                <ns2:e k="GPTA6">
                    <ns2:s v=""/>
                </ns2:e>
                <ns2:e k="GPTA7">
                    <ns2:s v=""/>
                </ns2:e>
                <ns2:e k="PLU">
                    <ns2:l v="10000"/>
                </ns2:e>
                <ns2:e k="GPTA8">
                    <ns2:s v=""/>
                </ns2:e>
                <ns2:e k="DYT">
                    <ns2:s v="SWEET &amp; SOUR SAUCE"/>
                </ns2:e>
            </ns2:payload>

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:1)

由于提供的示例格式不正确,我不得不修复您的XML。因此,您可能需要对此进行调整。

DECLARE @xml XML=
N'<ns2:pay xmlns:ns2="http://someurl.com/">
    <ns2:e k="BID">
        <ns2:l v="2"/>
    </ns2:e>
    <ns2:e k="PMD">
        <ns2:l v="1"/>
    </ns2:e>
    <ns2:e k="GPTA5">
        <ns2:s v=""/>
    </ns2:e>
    <ns2:e k="GPTA4">
        <ns2:s v=""/>
    </ns2:e>
    <ns2:e k="GPTA3">
        <ns2:s v="572"/>
    </ns2:e>
    <ns2:e k="GPTA1">
        <ns2:s v="Sweet &amp; Sour Sauce"/>
    </ns2:e>
    <ns2:e k="PFID">
        <ns2:l v="1"/>
    </ns2:e>
    <ns2:e k="EAN">
        <ns2:s v="010000"/>
    </ns2:e>
    <ns2:e k="PT">
        <ns2:s v="1"/>
    </ns2:e>
    <ns2:e k="TXID1">
        <ns2:l v="0"/>
    </ns2:e>
    <ns2:e k="PMN">
        <ns2:l v="1"/>
    </ns2:e>
    <ns2:e k="DID">
        <ns2:l v="1"/>
    </ns2:e>
    <ns2:e k="GPTA6">
        <ns2:s v=""/>
    </ns2:e>
    <ns2:e k="GPTA7">
        <ns2:s v=""/>
    </ns2:e>
    <ns2:e k="PLU">
        <ns2:l v="10000"/>
    </ns2:e>
    <ns2:e k="GPTA8">
        <ns2:s v=""/>
    </ns2:e>
    <ns2:e k="DYT">
        <ns2:s v="SWEET &amp; SOUR SAUCE"/>
    </ns2:e>
</ns2:pay>';

-此查询将返回所有属性及其名称(经典键值列表)

WITH XMLNAMESPACES('http://someurl.com/' AS ns2)
SELECT e.value('@k','nvarchar(max)') AS AttributeName
      ,e.value('(ns2:l/@v)[1]','nvarchar(max)') AS AttributeValue
FROM @xml.nodes(N'/ns2:pay/ns2:e') A(e);

-此查询使您可以选择一个给定键的值

DECLARE @FindThis NVARCHAR(100)='BID';
WITH XMLNAMESPACES('http://someurl.com/' AS ns2)
SELECT @xml.value(N'(/ns2:pay/ns2:e[@k=sql:variable("@FindThis")]/ns2:l/@v)[1]','int'); --use the proper type, if all values will be fine with this

-此查询将返回一个值表(只要您事先知道所有键)

WITH XMLNAMESPACES('http://someurl.com/' AS ns2)
SELECT @xml.value(N'(/ns2:pay/ns2:e[@k="BID"]/ns2:l/@v)[1]','int') AS BID
      ,@xml.value(N'(/ns2:pay/ns2:e[@k="PMD"]/ns2:l/@v)[1]','nvarchar(max)') AS PMD
      ,@xml.value(N'(/ns2:pay/ns2:e[@k="GPTA4"]/ns2:l/@v)[1]','nvarchar(max)') AS GPTA4
--add all keys in the same way...

更新

下面是一个示例,该示例使用PIVOT从表中读取,以表格形式显示:

提示:我使用NVARCHAR(1000)模拟您对cast即时运行的需求:

DECLARE @mockupTable TABLE(ID INT,YourData NVARCHAR(1000));
INSERT INTO @mockupTable VALUES
(1
,N'<ns2:pay xmlns:ns2="http://someurl.com/">
    <ns2:e k="BID">
        <ns2:l v="2"/>
    </ns2:e>
    <ns2:e k="PMD">
        <ns2:l v="1"/>
    </ns2:e>
    <ns2:e k="GPTA5">
        <ns2:s v=""/>
    </ns2:e>
    <ns2:e k="GPTA4">
        <ns2:s v=""/>
    </ns2:e>
    <ns2:e k="GPTA3">
        <ns2:s v="572"/>
    </ns2:e>
    <!--shortened for brevity-->
</ns2:pay>')
,(2
,N'<ns2:pay xmlns:ns2="http://someurl.com/">
    <ns2:e k="BID">
        <ns2:l v="20"/>
    </ns2:e>
    <ns2:e k="PMD">
        <ns2:l v="10"/>
    </ns2:e>
    <ns2:e k="GPTA5">
        <ns2:s v="bla"/>
    </ns2:e>
    <ns2:e k="GPTA4">
        <ns2:s v=""/>
    </ns2:e>
    <ns2:e k="GPTA3">
        <ns2:s v="572"/>
    </ns2:e>
    <!--shortened for brevity-->
</ns2:pay>');

-查询将创建一个键值列表,并将行的ID作为分组因子

WITH XMLNAMESPACES('http://someurl.com/' AS ns2)
SELECT p.*
FROM
(
    SELECT ID
          ,e.value('@k','nvarchar(max)') AS AttributeName
          ,e.value('(ns2:l/@v)[1]','nvarchar(max)') AS AttributeValue
    FROM @mockupTable t
    --the cast happens here
    CROSS APPLY(SELECT CAST(t.YourData AS XML)) A(TheXml)
    --the call to .nodes() happens here to return a derived table
    CROSS APPLY TheXml.nodes(N'/ns2:pay/ns2:e') B(e)
) tbl
PIVOT(MAX(AttributeValue) 
      FOR AttributeName 
      IN(BID,PMD,GPTA3,GPTA4,GPTA5) --add your columns here, order does not matter
) p