SQL服务器中的XQuery执行SUM超过零值

Veg*_*und 11 xml t-sql sql-server xquery

我正在尝试提取存储在一些格式不合理的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
Run Code Online (Sandbox Code Playgroud)

给出总和3时:

select xml.value('sum(/List/value)', 'numeric') sum
from (select cast('<List><value>0</value><value>0</value></List>' as xml) xml) a
Run Code Online (Sandbox Code Playgroud)

引发错误:"将数据类型nvarchar转换为数字时出错."

在总结一个零值节点列表时,我知道如何让我的查询返回0?

wcm*_*wcm 7

您的评论建议您解决问题.

而不是转换为数字,转换为浮点数.科学记数法将转换为浮动.


Tao*_*Tao 5

我在研究整数的类似问题时偶然发现了这个问题,并最终找到了答案。尽管自上次回答以来出现了延迟,但我还是在此处添加了内容,以防将来对其他人有帮助。

首先你的基本答案:

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
Run Code Online (Sandbox Code Playgroud)

在 XQuery 中,您可以将值转换为标准 XML 模式类型,然后 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
Run Code Online (Sandbox Code Playgroud)

(您无法让 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
Run Code Online (Sandbox Code Playgroud)

更新:我上面发布的小数处理解决方案的问题(在 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
Run Code Online (Sandbox Code Playgroud)

(结果为“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
Run Code Online (Sandbox Code Playgroud)

(结果为“2000000000000000000000000002”,正确的值)