额外的 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数据类型转换为关系数据集。 如果您想将各种<item>
节点作为派生集返回,这是一个很好的方法。在这种情况下,我会将名称和值作为典型的 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
,但使用谓词过滤<item>
,其中有一个具有给定名称的键。使用此<item>
,我们更深入地了解<value>
并阅读其内容。
【讨论】:
以上是关于额外的 XML 数据键值对到 SQL的主要内容,如果未能解决你的问题,请参考以下文章
Concat json to promise:如何从promise挂起的json对象中获取额外的键值对