【问题标题】:extra XML data key value pairs to SQL额外的 XML 数据键值对到 SQL
【发布时间】:2019-10-03 14:25:45
【问题描述】:

这是我试图从中提取的 XML

<?xml version="1.0" encoding="utf-16"?>
<dictionary>
<item>
<key><string>MemberNumber</string></key>
<value><string>66962336209</string></value>
</item></dictionary>

创建表#1(ID int identity(1,1),extradata xml)

INSERT INTO #1
Select '<dictionary><item><key><string>MemberNumber</string></key><value><string>66962336209</string></value></item></dictionary>'


SELECT extradata.value('/*:dictionary[1]/*:Item[1]/*:Key[1]','NVARCHAR(MAX)')
FROM #1;

select
    a.c.value('*:Value[1]','nvarchar(max)') as [value]
from #1 as t
    outer apply t.extradata.nodes('
        *:dictionary/*:Item[*:Key="code"]'
    ) as a(c)

我不断得到 NULL 值。

我想获取两个不同行上的键值对,我可以从那里转换数据。

【问题讨论】:

    标签: sql sql-server xml


    【解决方案1】:

    您的 SQL 代码使用通配符命名空间,尽管您的示例 XML 没有任何命名空间。此外,XPath 表达式完全关闭。 请尝试以下方法:

    SQL

    -- DDL and sample data population, start
    DECLARE @tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, xml_data XML);
    INSERT INTO @tbl (xml_data)
    VALUES
    (N'<dictionary>
        <item>
            <key>
                <string>MemberNumber</string>
            </key>
            <value>
                <string>66962336209</string>
            </value>
        </item>
    </dictionary>');
    -- DDL and sample data population, end
    
    SELECT ID
        , col.value('(value/string/text())[1]','VARCHAR(30)') AS [value]
    FROM @tbl tbl
        CROSS APPLY tbl.[xml_data].nodes('/dictionary/item[key/string/text() = "MemberNumber"]') AS tab(col);
    

    输出:

    +----+-------------+
    | ID |    value    |
    +----+-------------+
    |  1 | 66962336209 |
    +----+-------------+
    

    【讨论】:

    • 如果我得到正确的 OP,他想得到两列中的键和值。所以.nodes() 只是下降到/dictionary/item,然后是.value() 两者......可能是我弄错了......
    • @Shnugo,我们等待回复
    【解决方案2】:

    谢谢,有帮助。 xml 提取的新功能是将来自不同来源的代码放在一起。还添加了键名。

    DECLARE @tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, xml_data XML);
    INSERT INTO @tbl (xml_data)
    VALUES
    (N'<dictionary>
        <item>
            <key>
                <string>MemberNumber</string>
            </key>
            <value>
                <string>66962336209</string>
            </value>
        </item>
    </dictionary>');
    -- DDL and sample data population, end
    
    SELECT ID
        , col.value('(key/string/text())[1]','VARCHAR(30)') AS [key]
        , col.value('(value/string/text())[1]','VARCHAR(30)') AS [value]
    FROM @tbl tbl
        CROSS APPLY tbl.[xml_data].nodes('/dictionary/item[key/string/text() = "MemberNumber"]') AS tab(col);
    

    【讨论】:

    • 称为切分,即将XML数据类型转换为关系数据集。
    • 如果您想将各种&lt;item&gt; 节点作为派生集返回,这是一个很好的方法。在这种情况下,我会将名称和值作为典型的 key-value-pair 返回,并使用标准 SQL 方法来过滤此集合。但看起来好像您正在读取给定名称的一个值。在不需要.nodes()... 的情况下这样做应该会更快
    【解决方案3】:

    我想换一个:

    (感谢 Yitzhak Khabinsky 的 MCVE - 我这边 +1):

    DECLARE @tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, xml_data XML);
    INSERT INTO @tbl (xml_data)
    VALUES
    (N'<dictionary>
        <item>
            <key>
                <string>MemberNumber</string>
            </key>
            <value>
                <string>66962336209</string>
            </value>
        </item>
    </dictionary>');
    

    --我们可以使用一个外部变量来使其更通用

    DECLARE @KeyName VARCHAR(100)='MemberNumber';
    

    --查询

    SELECT t.ID
          ,t.xml_data.value('(/dictionary
                              /item[key/string/text()=sql:variable("@KeyName")] 
                              /value
                              /string
                              /text())[1]','varchar(30)')
    FROM @tbl t
    --This WHERE is not mandatory, but it might speed things up 
    --(if there are many items and many rows without this key)
    WHERE t.xml_data.exist('/dictionary[item/key/string/text()=sql:variable("@KeyName")]')=1;
    

    简而言之:

    • 我们声明了我们正在寻找的键名。这允许使用变量来获得更通用的方法。
    • WHERE 子句调用.exist()。试试看。您不需要这个,但它可能会提高一些速度(取决于您的数据)。
    • .value() 函数正在降级为/dictionary/item,但使用谓词过滤&lt;item&gt;,其中有一个具有给定名称的键。使用此&lt;item&gt;,我们更深入地了解&lt;value&gt; 并阅读其内容。

    【讨论】:

      猜你喜欢
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多