Я наткнулся на этот вопрос и, в конечном счете, на ответ, глядя на аналогичную проблему с целыми числами. Несмотря на задержку с момента последнего ответа, я добавляю сюда, если это поможет кому-то еще в будущем.
Сначала ваш основной ответ:
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-схемы, который затем будет корректно обрабатываться 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, вы должны явно указать его)
Наконец, фактическая проблема, которую мне лично нужно было решить, была почти такой же, за исключением того, что я имел дело с целыми числами, которые также борются с представлением "0" в xml 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
ОБНОВЛЕНИЕ: Проблема с решением для обработки десятичных чисел, которое я выложил выше (преобразование в десятичное число в XQuery до того, как SQL получит синтаксический анализ значения), заключается в том, что агрегирование фактически происходит с (предполагаемый / предполагаемый) тип данных с плавающей точкой (двойной). Если значения, которые вы сохранили в своем XML-файле, требуют высокой степени точности, это может быть неправильным решением - агрегирование с плавающей запятой может фактически привести к потере данных. Например, здесь мы теряем последнюю цифру суммируемого нами числа:
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
(выходит "2000000000000000000000000000", что неверно)
Эта проблема в равной степени относится и к другим подходам, предлагаемым здесь, таким как явное чтение значения как «float» в T-SQL.
Чтобы избежать этого, вот последний вариант, использующий выражение 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
(выходит "2000000000000000000000000002", правильное значение)