У чому полягає відмінність від простого дублювання функцій видалення з точки зору
Крім того, що на відміну від того 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
Я писав про цю тему більш глибоко в публікації в блозі