В чем разница с точки зрения простого удаления дубликатов?
Помимо того факта, что в отличие от 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
Я подробнее об этой теме написано в блоге
person
Lukas Eder
schedule
23.08.2017
SELECT c FROM myTbl UNION SELECT c FROM myTblи получить тот же результат ... Но зачем все усложнять, когда SELECT DISTINCT так просто. - person jarlh   schedule 05.07.2017GROUP BYнамного раньше, чем «SELECT», аDISTINCTследует за выбором. - person Paul Maxwell   schedule 20.10.2017DISTINCTприводит к фактическому выбору поля, то есть значение появится в наборе результатов.GROUP BYможет эффективно удалять дубликаты без фактического выбора поля. В большинстве случаев это неактуально, но в других может быть именно то, что вам нужно. Если вы в конечном итоге используетеGROUP BYвместоDISTINCT, вероятно, потребуется пояснительный комментарий в коде. - person rinogo   schedule 01.05.2018