额外的 XML 数据键值对到 SQL

Posted

技术标签:

【中文标题】额外的 XML 数据键值对到 SQL【英文标题】:extra XML data key value pairs to 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 值。

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

【问题讨论】:

【参考方案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; 并阅读其内容。

【讨论】:

以上是关于额外的 XML 数据键值对到 SQL的主要内容,如果未能解决你的问题,请参考以下文章

从 sql BigQuery 中的数组对象中获取键值对

SQL - 从键值对中提取值到数组

Concat json to promise:如何从promise挂起的json对象中获取额外的键值对

传递键值对是不是也可以防止 SQL 注入攻击?

使用带有 sql 的键值对搜索 php 多维关联数组,例如 '%LIKE%' 构造

mybatia的mypper.xml文件,参数类型为map,map里有一个键值对的值为数组,如何解析,例子可供参考