То, что вы не совсем понимаете в своем запросе / подходе, - это то, что вам на самом деле нужны два разных уровня группировки в одинаковых результатах строки запроса. Подзапросный подход наполовину прав, но когда вы выполняете подзапрос, который группирует, внутри другого запроса, который группирует, вы можете использовать только те данные, которые вы уже получили (из подзапроса), и вы можете только сохранить их на уровне агрегирования. подробно это уже есть, или вы можете потерять точность в пользу группировки больше. Вы не можете сохранить детали И потерять детали, чтобы подвести итоги. Следовательно, запрос подзапроса (с практической точки зрения) является относительно бессмысленным, поскольку вы можете сгруппировать его до уровня, который вы хотите, одним нажатием:
SELECT groupkey1, sum(y) FROM
(SELECT groupkey1, groupkey2, sum(x) as y FROM table GROUP BY groupkey1, groupkey2)
GROUP BY groupkey1
Так же, как:
SELECT groupkey1, sum(x) FROM
table
GROUP BY groupky1
Ответ Гордона, вероятно, сработает (за исключением той же ошибки, которую вы демонстрируете в том, что набор группировки неправильный / не охватывает все столбцы), но он, вероятно, не очень помогает с точки зрения вашего понимания, потому что это код только ответ. Вот пример того, как вам нужно подходить к этой проблеме, но с более простыми данными и вышеупомянутыми оконными функциями в пользу того, что вы уже знаете.
Предположим, на складе есть яблоки и дыни разных видов. Вы хотите запрос, который дает общее количество каждого конкретного вида фруктов, независимо от даты покупки. Вы также хотите столбец для общего итога для каждого типа фруктов:
Detail:
fruit | type | purchasedate | count
apple | golden delicious | 2017-01-01 | 3
apple | golden delicious | 2017-01-02 | 4
apple | granny smith | 2017-01-04 ! 2
melon | honeydew | 2017-01-01 | 1
melon | cantaloupe | 2017-01-05 | 4
melon | cantaloupe | 2017-01-06 | 2
Итак, это 7 вкусных золотых, 2 бабушки Смит, 1 медвяная роса, 6 дынь, а также 9 яблок и 7 дынь
Вы не можете сделать это как один запрос *, потому что вы хотите два разных уровня группировки. Вы должны сделать это в виде двух запросов, а затем (критическая точка понимания) вы должны объединить менее точные (яблоки / дыни) результаты с более точными (бабушка кузнецы / золотой вкусный / honydew / канталупа):
SELECT * FROM
(
SELECT fruit, type, sum(count) as fruittypecount
FROM fruit
GROUP BY fruit, type
) fruittypesum
INNER JOIN
(
SELECT fruit, sum(count) as fruitcount
FROM fruit
GROUP BY fruit
) fruitsum
ON
fruittypesum.fruit = fruitsum.fruit
Вы получите это:
fruit | type | fruittypecount | fruit | fruitcount
apple | golden delicious | 7 | apple | 9
apple | granny smith | 2 | apple | 9
melon | honeydew | 1 | melon | 7
melon | cantaloupe | 6 | melon | 7
Следовательно, для вашего запроса, различные группы, детали и резюме:
SELECT
detail.order || '-' || detail.ordinal_number as order,
detail.company,
summary.order_total,
detail.order_shipment_total,
detail.order_type
FROM (
SELECT o.order,
osh.ordinal_number,
o.company,
SUM(osh.items) AS order_shipment_total,
o.order_type
FROM orders o
JOIN order_shipments osh ON o.order_id = osh.order_id
WHERE o.order = [some order number]
GROUP BY o.order,
o.company,
o.order_type
) detail
INNER JOIN
(
SELECT o.order,
SUM(osh.items) AS order_total
FROM orders o
JOIN order_shipments osh ON o.order_id = osh.order_id
--don't need the where clause; we'll join on order number
GROUP BY o.order,
o.company,
o.order_type
) summary
ON
summary.order = detail.order
В запросе Гордона используется оконная функция для достижения того же эффекта; оконная функция запускается после завершения группировки и устанавливает другой уровень группировки (PARTITION BY ordernumber
), который является эффективным эквивалентом моего GROUP BY ordernumber
в сводке. Сводные данные оконной функции по своей сути связаны с подробными данными через порядковый номер; подразумевается, что запрос говорит:
SELECT
ordernumber,
lineitemnumber,
SUM(amount) linetotal
sum(SUM(amount)) over(PARTITION BY ordernumber) ordertotal
GROUP BY
ordernumber,
lineitemnumber
.. будет иметь ordertotal
, который является суммой всех linetotal
в заказе: GROUP BY подготавливает данные к детализации на уровне строки, а оконная функция подготавливает данные только к уровню заказа, и повторяет общее количество, необходимое для заполнения каждой позиции. Я написал SUM
, который принадлежит операции GROUP BY в заглавных буквах. sum
в нижнем регистре относится к операции разбиения. он должен sum(SUM())
и не может просто сказать sum(amount)
, потому что количество как столбец не разрешено само по себе - оно не входит в группу по. Поскольку количество само по себе не разрешено и его нужно СУММАТЬ, чтобы группа работала, нам нужно sum(SUM())
для запуска раздела (он запускается после того, как группа сделана)
Он ведет себя точно так же, как группировка на два разных уровня и объединение, и я действительно выбрал этот способ, чтобы объяснить это, потому что он делает более понятным, как он работает относительно того, что вы уже знаете о группах и объединениях
Помните: СОЕДИНЕНИЯ заставляют наборы данных расти вбок, СОЕДИНЕНИЯ заставляют их расти вниз. Если у вас есть некоторые подробные данные, и вы хотите увеличить их в сторону, добавив дополнительные данные (сводные данные), присоединитесь к ним. (Если бы вы хотели, чтобы итоги шли внизу каждого столбца, они были бы объединены)
* вы можете сделать это как один запрос (без оконных функций), но это может стать ужасно запутанным, потому что требует всевозможных хитростей, которые в конечном итоге не стоят этого, потому что слишком сложно поддерживать