SQL Server 中的 XQuery 对零值进行 SUM
Posted
技术标签:
【中文标题】SQL Server 中的 XQuery 对零值进行 SUM【英文标题】:XQuery in SQL server doing SUM over zero value 【发布时间】:2010-10-25 06:54:01 【问题描述】:我正在尝试提取存储在一些格式不正确的 xml 列中的货币金额(我猜没有为 XML 列定义模式,这是问题的一部分)。每当我遇到一个值为 0 的节点时,都会出现转换错误。
例子:
select xml.value('sum(/List/value)', 'numeric') sum
from (select cast('<List><value>1</value><value>2</value></List>' as xml) xml) a
给出总和 3 而:
select xml.value('sum(/List/value)', 'numeric') sum
from (select cast('<List><value>0</value><value>0</value></List>' as xml) xml) a
引发错误:“将数据类型 nvarchar 转换为数字时出错。”
知道如何在汇总零值节点列表时使查询返回 0 吗?
【问题讨论】:
当总和为零并且该数字无法转换为数字时,sum(/List/value) 似乎返回一个浮点数“0.0E0”。知道为什么我会看到这种行为吗? 【参考方案1】:您的评论为您的问题提供了答案。
不是转换为数字,而是转换为浮点数。科学计数法将转换为浮点数。
【讨论】:
【参考方案2】:你也可以像这样使用 if 语句:
@x.value('if (sum(/List/value) = 0) then 0 else sum(/List/value)', 'numeric')
【讨论】:
【参考方案3】:我偶然发现了这个问题,并最终得到了答案,同时查看了一个与整数类似的问题。尽管自上次回答以来有所延迟,但我还是在这里添加以防将来对其他人有所帮助。
首先你的基本答案:
select xml.value('xs:decimal(sum(/List/value))', 'numeric') sum
from (select cast('<List><value>0</value><value>0</value></List>' as xml) xml) a
在 XQuery 中,您可以将值转换为标准 XML Schema 类型,然后由 SQL Server 正确处理。
请注意:SQL Server 中的默认“数字”没有任何小数位(“0”的刻度)!您可能打算做更多类似的事情:
select xml.value('xs:decimal(sum(/List/value))', 'numeric(20,5))') sum
from (select cast('<List><value>0</value><value>0</value></List>' as xml) xml) a
(您无法让 SQL Server 从 Xml 返回的值推断精度或小数位数,您必须明确指定)
最后,我个人需要解决的实际问题几乎完全相同,只是我处理的是整数,这也与“0”double
值的 xml 表示形式有关:
select xml.value('xs:int(sum(/List/value))', 'int') sum
from (select cast('<List><value>0</value><value>0</value></List>' as xml) xml) a
更新: 我在上面发布的十进制处理解决方案的问题(在 SQL 解析值之前在 XQuery 中转换为十进制)是 聚合 实际上发生了使用(假设/推断)浮点(双)数据类型。如果您存储在 Xml 中的值需要高精度,那么这实际上可能是错误的做法 - 浮点聚合实际上可能会导致数据丢失。 EG 在这里我们丢失了我们求和的数字的最后一位:
select xml.value('xs:decimal(sum(/List/value))', 'numeric(28, 0)') sum
from (select cast('<List>
<value>1000000000000000000000000001</value>
<value>1000000000000000000000000001</value>
</List>' as xml) xml) a
(输出为“2000000000000000000000000000”,这是错误的)
此问题同样适用于此处提供的其他方法,例如在 T-SQL 中将值显式读取为“float”。
为避免这种情况,这是使用 XQuery FLWOR 表达式在聚合操作之前设置数据类型的最后一个选项。在这种情况下,聚合发生正确,并且我们有正确的求和值(同时如果/当它们发生时也处理“0”值):
select xml.value('sum(for $r in /List/value return xs:decimal($r))', 'numeric(28, 0)') sum
from (select cast('<List>
<value>1000000000000000000000000001</value>
<value>1000000000000000000000000001</value>
</List>' as xml) xml) a
(得出“2000000000000000000000000002”,正确值)
【讨论】:
我喜欢这里使用 XQuery 将值转换为标准 XML Schema 类型的方法。这正是我一直在寻找的,并且更喜欢将其转换为浮点数,然后再转换为其他东西。它更明确一点,但我可以避免将其移至一种类型,然后移至另一种类型,我认为这样更清楚。以上是关于SQL Server 中的 XQuery 对零值进行 SUM的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Sql Server XQuery 搜索不区分大小写的单词?
使用 JDBC 的 Xquery -- 错误的 SQL 语法