我正在尝试提取存储在一些格式不合理的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?
您的评论建议您回答问题。
而不是转换为数字,转换为浮点数。科学记数法将转换为浮动。
你也可以像这样使用if语句:
@x.value('if (sum(/List/value) = 0) then 0 else sum(/List/value)', 'numeric')
我偶然发现了这个问题,最终得到了一个答案,同时用整数查看了类似的问题。尽管自上一个答案以来有所延迟,我还是在这里添加,以防将来帮助其他人。
首先你的基本答案:
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返回的值中推断出精度或比例,您必须明确指定它)
最后,我个人需要解决的实际问题几乎完全相同,除了我处理的是整数,它也很难用xml表示“0” double
值:
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
(出来“20000000000000000000000000”,这是错的)
此问题同样适用于此处提供的其他方法,例如在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
(出来“200000000000000000000002”,正确值)