Jaka jest różnica z punktu widzenia zwykłej funkcjonalności usuwania duplikatów
Oprócz tego, że w przeciwieństwie do DISTINCT, GROUP BYpozwala 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 SELECTinstrukcji .
Oto najważniejsze operacje:
FROM(w tym JOIN, APPLYetc.)
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 BYdziałanie zachodzi „przed”, w SELECTpracy (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. DISTINCTOperacja „dzieje się po” projekcji, więc nie możemy już usunąć DISTINCTocen, 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