Суммируйте с помощью XQuery

Я использую XQuery для выполнения сложения. Ниже приведена структура XML, сохраненного в базе данных:

    <Events>
        <Event>
            <id>1</id>
            <code>1001</code>
            <Amount>50,1</Amount>
        </Event>
        <Event>
            <id>1</id>
            <code>1002</code>
            <Amount>5,5</Amount>
        </Event>
             <Event>
            <id>1</id>
            <code>1001</code>
            <Amount>50,1</Amount>
        </Event>
        <Event>
            <id>1</id>
            <code>1002</code>
            <Amount>5,5</Amount>
        </Event>
    </Events>

Я хочу получить результат ниже, используя XQuery: сумма суммы с одинаковым кодом. Обратите внимание, что , – это .. Мне нужно заменить , на . и выполнить арифметическую операцию.

 <Total>               
            <1001> 100,2 </1001>
            <1002> 11,0 </1002>
   </Total>

person Puru    schedule 18.05.2012    source источник
comment
Вам действительно нужны значения кода в качестве имен узлов? Не могли бы вы рассмотреть другую структуру вашего выходного XML, где у вас есть код как значение узла или значение атрибута?   -  person Mikael Eriksson    schedule 18.05.2012
comment
В вашем выводе у вас не может быть полных имен, начинающихся с цифры. Они должны начинаться либо с буквы, либо с подчеркивания.   -  person dan radu    schedule 18.05.2012
comment
Привет, Микаэль, я также могу использовать ‹Code›A1001‹/Code›. но мне нужны кодовые значения в качестве имен узлов.   -  person Puru    schedule 18.05.2012


Ответы (3)


Если ваш процессор XQuery поддерживает XQuery 3.0, используйте оператор group by.

<Total>
{
  for $i in //Event
  let $code := $i/code
  group by $code
  return element {"code"} { attribute {"id"} {$code}, sum($i/Amount)}
}
</Total>

В вашем вопросе есть два отличия от фрагментов XML: я изменил разделитель с плавающей запятой на точки (что необходимо, конечно, вы также можете сделать это с помощью некоторых строковых операций XQuery), и имена элементов могут состоять не только из чисел, иметь ознакомьтесь с правилами именования элементов. Вместо этого я решил вернуть код в качестве id-атрибута в моем примере.

person Jens Erat    schedule 18.05.2012
comment
Привет, Ранон, я хочу заменить на . и сделайте дополнение, не могли бы вы помочь мне в этом, я пытаюсь использовать функцию замены, но это дает мне ошибку SQL16003N. Выражение типа данных ( item(), item()+ ) не может использоваться, когда тип данных item() ожидается в контексте. Ошибка QName=ошибка:XPTY0004. - person Puru; 18.05.2012
comment
Спасибо, что попробовали сами, прежде чем спрашивать. :) Вероятно, вы использовали replace(...) в строке возврата. Replace ожидает одну строку, а не набор строк. Добавьте эту строку в операторы let: let $amount := number(replace($i/Amount, ",", ".")). Это заменяет двоеточие точкой и приводит к числу. в sum(...) суммируйте по $amount. - person Jens Erat; 18.05.2012
comment
Вы можете попробовать отредактированную версию решения в режиме реального времени по адресу zorba-xquery.com/html/. demo#4yAN48cPJqRgjJvmSlBOzdEe0hk= Кажется, все работает нормально. - person wcandillon; 18.05.2012
comment
Спасибо, Ранон, я добавил оператор let, но он дает ту же ошибку. :(. Не могли бы вы направить на это. - person Puru; 21.05.2012

Это даст вам данные в виде результирующего набора.

declare @X xml
set @X = 
'<Events>
        <Event>
            <id>1</id>
            <code>1001</code>
            <Amount>50,1</Amount>
        </Event>
        <Event>
            <id>1</id>
            <code>1002</code>
            <Amount>5,5</Amount>
        </Event>
             <Event>
            <id>1</id>
            <code>1001</code>
            <Amount>50,1</Amount>
        </Event>
        <Event>
            <id>1</id>
            <code>1002</code>
            <Amount>5,5</Amount>
        </Event>
    </Events>'

select T.code,
       sum(Amount) as Amount
from
  (
    select T.X.value('code[1]', 'int') as code,
           cast(replace(T.X.value('Amount[1]', 'varchar(13)'), ',', '.') as float) as Amount
    from @X.nodes('Events/Event') as T(X)
  ) as T
group by T.code
person Mikael Eriksson    schedule 18.05.2012

Следующий код рассчитает итоги и выведет результат в формате XML, но не в вашем выводе (что недопустимо):

SELECT Code AS 'Code', SUM(Value) AS 'Total'
FROM (
SELECT
    CONVERT(DECIMAL(9,2), REPLACE(c.value('Amount[1]', 'VARCHAR(10)'), ',', '.')) AS Value
    , c.value('code[1]', 'INT') AS Code
FROM @x.nodes('//Event') AS t(c)
) t
GROUP BY Code
FOR XML PATH('Total'), ROOT('Totals')

где @x — переменная XML, содержащая ваши данные.

person dan radu    schedule 18.05.2012