2009-05-11 11 views
11

Próbuję wyodrębnić pieniężne sumy przechowywane w źle sformatowanych kolumnach xml (nie ma schematu zdefiniowanego dla kolumny XML, która jak sądzę jest częścią problemu). Otrzymuję błąd konwersji, gdy napotkam węzeł z 0 jako jego wartością.XQuery na serwerze SQL robiąc SUMA o wartości zerowej

przykład:

select xml.value('sum(/List/value)', 'numeric') sum 
from (select cast('<List><value>1</value><value>2</value></List>' as xml) xml) a 

podaje sumę 3 przy czym:

select xml.value('sum(/List/value)', 'numeric') sum 
from (select cast('<List><value>0</value><value>0</value></List>' as xml) xml) a 

podnosi błąd "Błąd konwersji danych typu nvarchar na numeryczne"

Każdy pomysł, w jaki sposób mogę spowodować, że moje zapytanie zwróci 0 podczas podsumowywania listy węzłów o wartości zerowej?

+3

Wygląda na to, że suma (/ Lista/wartość) zwraca wartość "0,0E0", gdy suma wynosi zero i tej liczby nie można przekonwertować na wartość liczbową. Jakiś pomysł, dlaczego widzę to zachowanie? –

Odpowiedz

6

Twój komentarz sugeruje odpowiedź na twój problem.

Zamiast konwertować na numeryczne, konwertuj na zmienną. Notacja naukowa zamieni się w zmiennoprzecinkowy.

3

można także używać i if tak:

@x.value('if (sum(/List/value) = 0) then 0 else sum(/List/value)', 'numeric') 
3

natknąłem to pytanie, a ostatecznie odpowiedź, patrząc na podobny problem z całkowitymi. Pomimo opóźnienia od ostatniej odpowiedzi, dodam tutaj, na wypadek gdyby pomógł komukolwiek innemu w przyszłości.

Pierwszy podstawowy odpowiedź:

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 

W XQuery można oddać wartość do standardowego typu XML Schema, które następnie będą prawidłowo obsługiwane przez SQL Server.

UWAGA: domyślny "numeryczny" w Serwerze SQL nie ma żadnych miejsc dziesiętnych (skala "0")! Prawdopodobnie zamierzał zrobić coś więcej takich jak:

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 

(nie można uzyskać SQL Server wywnioskować precyzji lub skali od wartości zwracanej z XML, należy wyraźnie określić ją)

Wreszcie rzeczywisty problem, który ja osobiście potrzebne do adresu była niemal dokładnie takie same, z wyjątkiem miałem do czynienia z liczbami całkowitymi, które również borykają się z reprezentacją xml „0” double wartości:

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 

UPDATE: Problem z rozwiązaniem do obsługi dziesiętnej, które napisałem powyżej (konwersja na wartość dziesiętną w XQuery, zanim SQL zacznie analizować wartość), jest taka, że ​​agregacja zachodzi w rzeczywistości z (założonym/wnioskiem) typem danych zmiennoprzecinkowych (double). Jeśli wartości, które zapisałeś w swoim Xml, wymagają dużej precyzji, może to być niewłaściwe - agregacja zmiennoprzecinkowa może w rzeczywistości spowodować utratę danych. EG tutaj tracimy ostatnią cyfrę numeru jesteśmy podsumowującej:

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 

(wychodzi do „2000000000000000000000000000”, co jest źle)

Problem ten dotyczy w równym stopniu do innych rozwiązań oferowanych tutaj, jak wyraźnie odczytanie wartości jako "float" w T-SQL.

Aby tego uniknąć, oto ostatnia opcja przy użyciu wyrażenia XQuery FLWOR, aby ustawić typ danych przed operacją agregacji przed. W tym przypadku, agregacja zachodzi poprawnie i mamy prawidłowy zsumowane wartości (a także przenoszenia wartości „0” jeśli/kiedy występują):

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 

(wychodzi „2000000000000000000000000002”, prawidłowa wartość)

+0

Podoba mi się tutaj metoda używania XQuery do rzucania wartości do standardowego schematu XML. Właśnie tego szukałem i wolę to, zamiast przekształcić go w zmiennoprzecinkowe, a następnie wrócić do czegoś innego. Jest to trochę bardziej wyraźne, ale mogę uniknąć przeniesienia go do jednego typu, a potem do drugiego, i myślę, że jest to wyraźniejsze. – mttjohnson