在XML中求和节点的值时SQL Server的奇怪行为

时间:2013-04-22 11:21:01

标签: sql sql-server xml sql-server-2008

我问一个关于sum节点值的问题:

sum some xml nodes values in sql server 2008

请考虑以下代码:

Declare @xml xml 
set @xml='<Parent ID="p">
     <Child ID="1">1000000000</Child > 
     <Child ID="2">234650</Child > 
     <Child ID="3">0</Child > 
      </Parent >'

Select @xml.value('sum(/Parent[@ID="p"]/Child)','bigint') as Sum

如果执行此操作,则会重新发出此错误:

  

Msg 8114,Level 16,State 5,Line 8   将数据类型nvarchar转换为bigint时出错。

问题是它返回此值:1.00023465E9

如果我以这种方式更改上述查询就可以了:

Declare @xml xml 
set @xml='<Parent ID="p">
     <Child ID="1">1000000000</Child > 
     <Child ID="2">234650</Child > 
     <Child ID="3">0</Child > 
      </Parent >'

Select @xml.value('sum(/Parent[@ID="p"]/Child)','float') as Sum

为什么Sql Server会这样做?

4 个答案:

答案 0 :(得分:4)

Sql Server在使用科学记数法将值从字符串转换为整数时遇到问题,就像运行xpath查询时一样,但是,它可以为float执行此操作。

您可以像这样编写查询:

select @xml.value('sum(/Parent[@ID = "p"]/Child) cast as xs:long?', 'bigint')

答案 1 :(得分:2)

试试这个 -

DECLARE @xml XML 
SELECT @xml='<Parent ID="p">
     <Child ID="1">1000000000</Child > 
     <Child ID="2">234650</Child > 
     <Child ID="3">0</Child > 
      </Parent >'

SELECT @xml.value('sum(for $r in /Parent[@ID="p"]/Child return xs:int($r))', 'bigint')

<强>更新

DECLARE @xml XML 
SELECT @xml='<Parent ID="p">
     <Child ID="1">100000000000000</Child > 
     <Child ID="2">234650</Child > 
     <Child ID="3">0</Child > 
      </Parent >'

SELECT @xml.value('sum(for $r in /Parent[@ID="p"]/Child return xs:decimal($r))', 'bigint')

更新2:

DECLARE @xml XML 
SELECT @xml='<Parent ID="p">
     <Child ID="1">100000000000000.6</Child > 
     <Child ID="2">234650</Child > 
     <Child ID="3">0</Child > 
      </Parent >'

SELECT @xml.value('sum(for $r in /Parent[@ID="p"]/Child return xs:decimal($r))', 'decimal(18,2)')

答案 2 :(得分:0)

尝试使用BIGINT:

DECLARE @SearchKeyWords XML 

SET @SearchKeyWords =
'<Parent ID=''p''>
    <Child ID="1">1000000000</Child > 
    <Child ID="2">234650</Child > 
    <Child ID="3">0</Child > 
</Parent >' 

DECLARE @TempSearchKeyWords TABLE
        (
            SearchKeyWord BIGINT
        )

INSERT INTO @TempSearchKeyWords                     
SELECT SearchKeyWords.SearchKeyword.value('.',' bigint ') AS SearchKeyword             
FROM @SearchKeyWords.nodes('/Parent/Child') AS SearchKeyWords(SearchKeyword)

SELECT SUM(SearchKeyWord) FROM @TempSearchKeyWords

答案 3 :(得分:0)

您在此处使用的XML是无类型XML。这意味着提供给sum()的值的类型为xdt:untypedAtomic。在sum()上使用xdt:untypedAtomic时,值会转换为xs:doublesum()函数将values()的结果作为字符串(或untypedAtomic)读取,xs:double使用科学记数法,当值小于1.0E-6或大于或等于1.0E6。 SQL Server无法将科学记数法转换为intbigint

价:
sum Function (XQuery)
Type Casting Rules in XQuery

其他答案提供了变通方法,可以将sum()float的输入值或结果作为values()中的数据类型。另一种选择可能是使用类型化的XML。

架构:

create xml schema collection XSDSumTest as '
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Parent">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Child" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="xs:int">
                                <xs:attribute name="ID" type="xs:int"/>
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:attribute name="ID" type="xs:string"/>
        </xs:complexType>
    </xs:element>
</xs:schema>'

查询:

declare @xml xml(XSDSumTest) = '
<Parent ID="p">
  <Child ID="1">1000000000</Child > 
  <Child ID="2">234650</Child > 
  <Child ID="3">0</Child > 
</Parent>'

select @xml.value('sum(/Parent[@ID="p"]/Child)','bigint') as Sum