Агрегировать / группировать строки таблицы в SQL, если столбец имеет определенное значение - PullRequest
1 голос
/ 22 апреля 2011

Я работаю с довольно волосатым Stored Proc, который возвращает XML (XML преобразуется с помощью таблицы стилей и распечатывается на странице; по сути, это GridView в XML).У меня есть требование объединить несколько строк (с одним и тем же идентификатором, конечно) в одну строку , только если значение определенного столбца не является одним из двух конкретных значений (в этом случае столбцы не являютсяагрегировано).

По сути, мне нужно сделать следующее (в псевдокоде):

select quoteID, customerName, shippingCharges, description, /*other columns*/
from quotes q
    inner join customers c on q.customerID = c.customerID
where shipDate between @fromDate and @toDate
for xml explicit

if description != "Insurance" and description != "Pickup":
    /*aggregate the rows for that quoteID into one single row
      adding together charges and the like as needed*/  
else:
    /*nothing - okay to have multiple rows*/

Как мне поступить с обработкой логики этого типа?Моим первым предположением было бы поместить все значения во временную таблицу (или CTE), а затем каким-то образом проверить все данные, чтобы увидеть, нужно ли мне извлекать и комбинировать строки, но я рисую пробел относительно того, как это на самом деле делается, что обычно является показателем того, что не правильный способ сделать это ...

Было бы лучше (и, возможно, проще?) сделать это вместо файла преобразования XSL?Мой выбор ограничен тремя вариантами:

  1. Агрегировать в хранимой процедуре, оставить XSLT нетронутым
  2. Агрегировать в XSLT, оставить хранимую процедуру нетронутой
  3. Это может 'не может быть достигнуто способом, которым данные возвращаются в настоящее время (или не могут быть достигнуты без большого количества трудоемких обходных путей)

РЕДАКТИРОВАТЬ

Oneиз проблем, с которыми я сталкиваюсь, является то, что записи обычно имеют одинаковое поле идентификатора, и поэтому итоговые значения получаются неверными, потому что я суммирую всю запись (которая вычисляет сумму для поля, которое я хочу и поле, которое мне не нужно).

Например, запись может выглядеть примерно так:

1234    Insurance           54.65
1234    Shipping Charge     160.00
1234    Some Other Charge   15.00

, и я бы хотел, чтобы конечный результат был таким:

1234    Shipment    175.00
1234    Insurance   54.65

что происходит так:

1234    Shipment    229.65
1234    Insurance   229.65

и это сбрасывает итоги.

Стратегия, которую я использовал, заключалась в создании CTE с именем AggregateData, который суммируетразличные суммы и грпо идентификатору и описанию;это терпит неудачу, потому что это дает вышеупомянутый результат (суммы для каждого описания, таким образом, значение появляется дважды и добавляется дважды в отчет).Самое близкое, что я получил, - это НЕ группировать его по описанию, а вместо этого обернуть его в функцию Max (Да, я знаю, что это не очень хорошая идея).Это дает мне правильные итоги, но описание точно не отражается, например, некоторые записи должны быть «Страхование», но вместо этого отображаются «Отгрузка».

Ответы [ 2 ]

5 голосов
/ 22 апреля 2011

Самый простой способ - написать два запроса и объединить результаты

select <columns>
where description not in('Insurance','Pickup')
group by  <some columns)
union all
select <columns>
where description in('Insurance','Pickup')
0 голосов
/ 03 мая 2011

Может быть, что-то вроде этого:

SELECT
  customerName,
  quoteID,
  description = CASE
    WHEN description IN ('Insurance', 'Pickup') THEN description
    ELSE 'Shipment'
  END,
  shippingCharges = SUM(shippingCharges)
FROM quotes q
  INNER JOIN customers c ON q.customerID = c.customerID
GROUP BY
  customerName,
  quoteID,
  CASE
    WHEN description IN ('Insurance', 'Pickup') THEN description
    ELSE 'Shipment'
  END

Вы, должно быть, заметили, что одно и то же выражение CASE здесь повторяется дважды. Вы можете избежать этого, используя обычный подпункт:

SELECT
  customerName,
  quoteID,
  description,
  shippingCharges = SUM(shippingCharges)
FROM (
  SELECT
    customerName,
    quoteID,
    description = CASE
      WHEN description IN ('Insurance', 'Pickup') THEN description
      ELSE 'Shipment'
    END,
    shippingCharges = SUM(shippingCharges)
  FROM quotes q
    INNER JOIN customers c ON q.customerID = c.customerID
) s
GROUP BY
  customerName,
  quoteID,
  description

или CTE:

WITH preparedList AS (
  SELECT
    customerName,
    quoteID,
    description = CASE
      WHEN description IN ('Insurance', 'Pickup') THEN description
      ELSE 'Shipment'
    END,
    shippingCharges = SUM(shippingCharges)
  FROM quotes q
    INNER JOIN customers c ON q.customerID = c.customerID
)
SELECT
  customerName,
  quoteID,
  description,
  shippingCharges = SUM(shippingCharges)
FROM preparedList
GROUP BY
  customerName,
  quoteID,
  description

При необходимости вы также можете добавить другие столбцы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...