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 【问题描述】:

我有一个表,其中包含一个名为 SettingsXML 数据类型列。 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 子句中使用它的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JS 获取不同的值并在 JSON 上求和

我们如何组合来自相同 data_type 的数据帧的两列的值并获取每个元素的计数?

如何在 DB2 Sql 中的上一列下方获取下一列的值

如何分解数据库中的值并在选择查询中使用它?

sql选择某一列的最大值与最小值并在同一列中显示

如何使用 Bootstrap Multiselect 获取所有选定的值并在 AJAX 中使用它