SQL 如何获取 XML 数据列的值并在 where 子句中使用它
Posted
技术标签:
【中文标题】SQL 如何获取 XML 数据列的值并在 where 子句中使用它【英文标题】:SQL How to get value of XML data column and use it inside of the where clause 【发布时间】:2019-09-18 18:43:45 【问题描述】:我有一个表,其中包含一个名为 Settings
的 XML
数据类型列。 XML
数据的结构:
<root>
<Setting1>true</Setting1>
<Setting2>false</Setting2>
...
<root>
该表还有一个ID
列,我想用它来对我的结果进行分组。我想计算每个ID
有多少Setting1
配置设置为true
。 注意:ID
字段不是唯一的,可以重复。
这是我目前所拥有的:
with xmlnamespaces (DEFAULT '...')
select count(Setting1) as counts
from (select Settings.value('(/root/Setting1)[1]', 'nvarchar(max)') as Setting1
from MY_TABLE
group by ID) res
where Setting1= 'true'
但是我收到以下错误:
选择列表中的“MY_TABLE.Configuration”列无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。
【问题讨论】:
【参考方案1】:虽然你已经有了答案,但我想补充一些替代方案:
(模型归功于 Michal Turczyn)
declare @tbl table (id int, xmlCol xml);
insert into @tbl values
(1, '<root>
<Setting1>true</Setting1>
<Setting2>false</Setting2>
</root>'),
(1, '<root>
<Setting1>true</Setting1>
<Setting2>false</Setting2>
</root>'),
(2, '<root>
<Setting1>false</Setting1>
<Setting2>false</Setting2>
</root>'),
(2, '<root>
<Setting1>true</Setting1>
<Setting2>false</Setting2>
</root>');
最快的应该是简单的XML.exist()
:
SELECT t.id,
sum(CASE WHEN t.xmlCol.exist('/root/Setting1[text()="true"]')=1 THEN 1 ELSE 0 END) howManyTrue
FROM @tbl t
GROUP BY t.id
您可以使用变量来增强此功能,以便在语句之外设置 SettingName:
DECLARE @SettingName NVARCHAR(100)=N'Setting1';
SELECT t.id,
sum(CASE WHEN t.xmlCol.exist('/root/*[local-name()=sql:variable("@SettingName") and text()="true"]')=1 THEN 1 ELSE 0 END) howManyTrue
FROM @tbl t
GROUP BY t.id
--如果一个设置可能在一个 XML 中出现多次,您可以使用 XQuery 的count()
:
SELECT t.id,
sum(t.xmlCol.value('count(/root/*[local-name()=sql:variable("@SettingName") and text()="true"])','int')) howManyTrue
FROM @tbl t
GROUP BY t.id
【讨论】:
【参考方案2】:试试这个查询:
declare @tbl table (id int, xmlCol xml);
insert into @tbl values
(1, '<root>
<Setting1>true</Setting1>
<Setting2>false</Setting2>
</root>'),
(1, '<root>
<Setting1>true</Setting1>
<Setting2>false</Setting2>
</root>'),
(2, '<root>
<Setting1>false</Setting1>
<Setting2>false</Setting2>
</root>'),
(2, '<root>
<Setting1>true</Setting1>
<Setting2>false</Setting2>
</root>');
select id,
sum(convert(int, xmlCol.value('(/root//Setting1/node())[1]', 'bit'))) howManyTrue
from @tbl
group by id
【讨论】:
令人惊讶的是,没有记录 node() 函数:docs.microsoft.com/en-us/sql/xquery/… 你的回答很好(我这边+1),但我有一些评论:1)这不需要//Setting1
之前的深度搜索。并且 2),这在没有 /node()
的情况下也可以工作......并且 3) 比阅读 all 值我更喜欢 XML.exist()
或 XQuery 的 count()
更好(请参阅我的答案)。
@YitzhakKhabinsky 你知道具体情况吗,实际上需要node()
?它可能有助于复杂的 FLWOR 查询,但到目前为止我在任何地方都不需要它......
@Shnugo,这里也是。我不知道它存在。而且从来不需要它。
@Shnugo,让我烦恼的是 - 它没有记录在案。以上是关于SQL 如何获取 XML 数据列的值并在 where 子句中使用它的主要内容,如果未能解决你的问题,请参考以下文章