В чем отличие с точки зрения простого удаления дубликатов
Помимо того факта, что, в отличие от этого DISTINCT
, GROUP BY
допускается агрегирование данных по группам (что было упомянуто во многих других ответах), самым важным отличием, на мой взгляд, является тот факт, что две операции «происходят» на двух очень разных этапах в логическом порядке. операций, которые выполняются в SELECT
заявлении .
Вот самые важные операции:
FROM
( в том числе JOIN
, APPLY
и т.д.)
WHERE
GROUP BY
(можно удалить дубликаты)
- Скопления
HAVING
- Оконные функции
SELECT
DISTINCT
(можно удалить дубликаты)
UNION
, INTERSECT
, EXCEPT
(Можно удалить дубликаты)
ORDER BY
OFFSET
LIMIT
Как видите, логический порядок каждой операции влияет на то, что можно сделать с ней, и как она влияет на последующие операции. В частности, тот факт , что GROUP BY
операция «происходит до» на SELECT
операции (проекция) означает , что:
- Это не зависит от прогноза (что может быть преимуществом)
- Он не может использовать какие-либо значения из проекции (что может быть недостатком)
1. Это не зависит от проекции
Пример, в котором полезно не зависеть от проекции, - это если вы хотите рассчитать оконные функции по различным значениям:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating
При запуске с базой данных Sakila это дает:
rating rn
-----------
G 1
NC-17 2
PG 3
PG-13 4
R 5
Этого не может быть достигнуто с DISTINCT
легкостью:
SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
Этот запрос «неправильный» и дает что-то вроде:
rating rn
------------
G 1
G 2
G 3
...
G 178
NC-17 179
NC-17 180
...
Это не то, что мы хотели. DISTINCT
Операция «не происходит после того, как » проекция, поэтому мы больше не можем удалить DISTINCT
рейтинги , потому что функция окна уже рассчитаны и прогнозируемые. Чтобы использовать DISTINCT
, нам нужно было бы вложить эту часть запроса:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM (
SELECT DISTINCT rating FROM film
) f
Примечание: в данном конкретном случае мы могли бы также использоватьDENSE_RANK()
SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
FROM film
2. Он не может использовать какие-либо значения из проекции
Одним из недостатков SQL является его многословие. По той же причине, что мы видели раньше (а именно, логический порядок операций), мы не можем «легко» группировать то, что мы проецируем.
Это неверный SQL:
SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY name
Это верно (повторяет выражение)
SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY first_name || ' ' || last_name
Это также верно (вложенное выражение)
SELECT name
FROM (
SELECT first_name || ' ' || last_name AS name
FROM customer
) c
GROUP BY name
Я написал об этой теме более подробно в блоге