简体   繁体   中英

strange behavior of SQL Server when sum nodes's values in XML

I ask a question about sum node's values:

sum some xml nodes values in sql server 2008

Please consider this code:

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

if you execute this it retrun this error:

Msg 8114, Level 16, State 5, Line 8 Error converting data type nvarchar to bigint.

the problem is it return this value : 1.00023465E9

if I change the above query this way it being ok:

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

Why Sql Server do this?

Sql Server has a problem converting the value with scientific notation from a string to an integer, as would happen when you run your xpath query, however, it can do this for float .

You could write your query like this:

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

Try this one -

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')

UPDATE:

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')

UPDATE 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)')

Try this is working with 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

The XML you have here is untyped XML. That means the values provided to sum() is of type xdt:untypedAtomic . When sum() is used on xdt:untypedAtomic the values are cast to xs:double . The result of sum() is read by the values() function as a string (or untypedAtomic) and xs:double uses the scientific notation when the value is less than 1.0E-6, or greater than or equal to 1.0E6. SQL Server can not convert from scientific notation to int or bigint .

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

Other answers have provided workarounds that cast the input values or the result from sum() or using float as the data type in values() . Another option could be to use typed XML instead.

Schema:

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>'

Query:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM