Jaka jest różnica z punktu widzenia zwykłej funkcjonalności usuwania duplikatów
Oprócz tego, że w przeciwieństwie do DISTINCT
, GROUP BY
pozwala na agregowanie danych na grupę (o czym wspomniało wiele innych odpowiedzi), najważniejszą różnicą moim zdaniem jest fakt, że dwie operacje „zdarzają się” na dwóch bardzo różnych etapach w kolejności logicznej operacji wykonywanych w SELECT
instrukcji .
Oto najważniejsze operacje:
FROM
(w tym JOIN
, APPLY
etc.)
WHERE
GROUP BY
(może usunąć duplikaty)
- Agregacje
HAVING
- Funkcje okna
SELECT
DISTINCT
(może usunąć duplikaty)
UNION
, INTERSECT
, EXCEPT
(Można usunąć duplikaty)
ORDER BY
OFFSET
LIMIT
Jak widać, logiczna kolejność każdej operacji wpływa na to, co można z nią zrobić i jak wpływa na kolejne operacje. W szczególności, fakt, że GROUP BY
działanie zachodzi „przed”, w SELECT
pracy (projekcja) oznacza, że:
- To nie zależy od projekcji (co może być zaletą)
- Nie może używać żadnych wartości z rzutu (co może być wadą)
1. To nie zależy od projekcji
Przykładem, w którym nie jest zależne od rzutowania, jest użyteczny, jeśli chcesz obliczyć funkcje okna dla różnych wartości:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating
Po uruchomieniu z bazą danych Sakila daje to:
rating rn
-----------
G 1
NC-17 2
PG 3
PG-13 4
R 5
Tego samego nie da się DISTINCT
łatwo osiągnąć :
SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
To zapytanie jest „nieprawidłowe” i daje coś takiego:
rating rn
------------
G 1
G 2
G 3
...
G 178
NC-17 179
NC-17 180
...
Nie tego chcieliśmy. DISTINCT
Operacja „dzieje się po” projekcji, więc nie możemy już usunąć DISTINCT
ocen, ponieważ funkcja okno zostało już obliczone i prognozowanych. Aby użyć DISTINCT
, musielibyśmy zagnieździć tę część zapytania:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM (
SELECT DISTINCT rating FROM film
) f
Uwaga dodatkowa: W tym konkretnym przypadku moglibyśmy również użyćDENSE_RANK()
SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
FROM film
2. Nie można użyć żadnych wartości z rzutu
Jedną z wad SQL jest czasami jego gadatliwość. Z tego samego powodu, co widzieliśmy wcześniej (mianowicie logicznej kolejności operacji), nie możemy „łatwo” pogrupować według czegoś, co projektujemy.
To jest nieprawidłowy SQL:
SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY name
Jest to poprawne (powtarzanie wyrażenia)
SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY first_name || ' ' || last_name
Jest to również poprawne (zagnieżdżanie wyrażenia)
SELECT name
FROM (
SELECT first_name || ' ' || last_name AS name
FROM customer
) c
GROUP BY name
Bardziej szczegółowo napisałem na ten temat w poście na blogu