Usuwanie powtarzających się wierszy z wyniku zapytania słowem DISTINCT i pułapka porównywania całych wierszy, a nie pojedynczych kolumn.
Wynik zapytania często zawiera powtórzenia. Pytanie „jakie przedmioty są w tabeli ocen" zadane zwykłym SELECT zwróci nazwę przedmiotu tyle razy, ile jest z niego ocen – a nas interesuje sama lista, bez powtórzeń. Od tego jest słowo kluczowe DISTINCT.
DISTINCT stawia się zaraz po SELECT, przed listą kolumn. Baza wykonuje zapytanie normalnie, a na koniec usuwa z wyniku powtarzające się wiersze, zostawiając po jednym egzemplarzu każdego.
Reguła, którą trzeba zapamiętać: DISTINCT porównuje CAŁY wiersz wyniku, nie pojedynczą kolumnę. Dwa wiersze zostaną uznane za takie same tylko wtedy, gdy zgadzają się we wszystkich wypisanych kolumnach. Wystarczy, że w którejkolwiek różnią się choćby jednym znakiem, a oba zostaną w wyniku.
Stąd bierze się najczęstsze nieporozumienie. Zapytanie o same nazwiska z DISTINCT faktycznie zwróci listę unikalnych nazwisk. Ale gdy dopiszesz do listy kolumn imię, DISTINCT zacznie porównywać pary „imię plus nazwisko" – i dwie różne osoby o tym samym nazwisku obie zostaną w wyniku, bo różnią się imieniem. To poprawne działanie, tylko rzadko to, czego się spodziewano.
Odwrotna pułapka jest groźniejsza: DISTINCT nie odróżnia dwóch różnych osób o identycznych danych. Jeśli w tabeli są dwie różne uczennice nazywające się tak samo, DISTINCT skróci je do jednego wiersza – bo widzi wyłącznie wartości, nie rzeczywistość, którą opisują. Dlatego do liczenia osób służy klucz (id), a nie nazwisko.
Jeśli powtórzeń chcesz nie tyle usunąć, ile policzyć, właściwym narzędziem jest GROUP BY – grupowanie bez funkcji agregującej daje zresztą wynik bardzo podobny do DISTINCT.
-- Bez DISTINCT: przedmiot powtarza się tyle razy, ile jest z niego ocen SELECT przedmiot FROM oceny
| przedmiot |
|---|
| informatyka |
| matematyka |
| informatyka |
| informatyka |
| matematyka |
-- Z DISTINCT: sama lista przedmiotów SELECT DISTINCT przedmiot FROM oceny
| przedmiot |
|---|
| informatyka |
| matematyka |
-- DISTINCT patrzy na cały wiersz - tu na pary przedmiot + ocena SELECT DISTINCT przedmiot, ocena FROM oceny
| przedmiot | ocena |
|---|---|
| informatyka | 5 |
| matematyka | 4 |
| informatyka | 3 |
| informatyka | 6 |
| matematyka | 5 |
-- DISTINCT na prawdziwej tabeli uczniowie: klasy powtarzają się mimo różnych uczniów SELECT DISTINCT klasa FROM uczniowie
| klasa |
|---|
| 3A |
| 3B |
| 3C |
-- Warunek, którego nie spełnia żaden uczeń - DISTINCT nie tworzy wierszy znikąd SELECT DISTINCT klasa FROM uczniowie WHERE srednia > 6
| klasa |
|---|
| (brak wierszy) |
| W Accessie | Standardowy SQL | Znaczenie |
|---|---|---|
SELECT Count(*) FROM (SELECT DISTINCT kolumna FROM tabela) |
SELECT COUNT(DISTINCT kolumna) FROM tabela |
zliczenie liczby różnych wartości w kolumnie – obejście przez podzapytanie, bo Access nie przyjmuje DISTINCT jako argumentu Count |
| Cecha | DISTINCT | GROUP BY |
|---|---|---|
| Co robi | usuwa powtarzające się wiersze z gotowego wyniku | dzieli wiersze na grupy według wartości wskazanych kolumn |
| Można liczyć wewnątrz | nie – bez dodatkowego podzapytania nie policzy liczby grup | tak – naturalnie łączy się z funkcją agregującą (COUNT, SUM, AVG) na każdą grupę |
| Wynik bez funkcji agregującej | lista unikalnych wierszy | podobna lista unikalnych grup – wyniki obu bywają wtedy identyczne |
| Filtrowanie wyniku po wyliczonej wartości | niemożliwe – DISTINCT nic nie liczy | HAVING po wartości agregatu, patrz grupowanie GROUP BY |
| Kiedy wybrać | gdy trzeba tylko pozbyć się powtórzeń | gdy trzeba coś policzyć lub zsumować dla każdej grupy |
DISTINCT wstawione po nazwie kolumny, nie po SELECT. Zapytanie SELECT przedmiot DISTINCT FROM oceny to błąd składni – Access nie rozpozna takiej kolejności słów i zgłosi błąd zapytania. DISTINCT zawsze stoi zaraz po SELECT, przed pierwszą kolumną: SELECT DISTINCT przedmiot FROM oceny.
Dopisanie do SELECT kolumny z kluczem głównym. SELECT DISTINCT id_oceny, przedmiot FROM oceny wygląda jak próba usunięcia duplikatów przedmiotu, ale id_oceny jest unikalny dla każdego wiersza, więc DISTINCT porównuje pary „id plus przedmiot" – zawsze różne – i baza zwróci wszystkie wiersze bez żadnej redukcji. Duplikaty znikają dopiero po usunięciu kolumny z kluczem z listy SELECT.
Traktowanie DISTINCT jak funkcji liczącej. Na polecenie „ile jest różnych przedmiotów" część uczniów pisze SELECT DISTINCT przedmiot FROM oceny i na tym kończy, oczekując liczby. DISTINCT nigdy nie zwraca liczby – zwraca listę. Do samej liczby potrzebna jest funkcja agregująca, najlepiej COUNT.
Count(DISTINCT przedmiot) w Accessie. Ten zapis działa w wielu innych bazach, ale Access zgłasza błąd składni funkcji – nie przyjmuje DISTINCT jako argumentu funkcji agregującej. Trzeba go obejść podzapytaniem: najpierw wybrać unikalne wartości, dopiero potem je policzyć (patrz sekcja Dialekt).
Pominięcie DISTINCT po złączeniu kilku tabel. Gdy zapytanie łączy tabelę uczniów z tabelą ocen, każdy uczeń pojawia się tyle razy, ile ma ocen – bez DISTINCT lista „które klasy mają ucznia z oceną powyżej 5" powtórzy tę samą klasę wielokrotnie. Dopisanie DISTINCT na początku SELECT usuwa powielone wiersze, nie zmieniając reszty zapytania.
Mylenie DISTINCT z ograniczeniem UNIQUE. Zapis w rodzaju „kolumna email ma być DISTINCT" przy projektowaniu tabeli nie ma sensu – DISTINCT działa dopiero w zapytaniu SELECT i nic nie wymusza na danych zapisanych w tabeli. Żeby zagwarantować brak duplikatów w samej tabeli, potrzebne jest ograniczenie integralności nałożone na kolumnę, a nie słowo kluczowe zapytania.
Fragment tabeli oceny (te same dane co w przykładach wyżej, z dopisaną kolumną ucznia):
| uczen | przedmiot | ocena |
|---|---|---|
| Kowalska | informatyka | 5 |
| Nowak | matematyka | 4 |
| Wiśniewski | informatyka | 3 |
| Zając | informatyka | 6 |
| Dąbrowski | matematyka | 5 |
Uzupełnij odpowiedzi na podstawie tabeli oceny:
| Pytanie | Odpowiedź |
|---|---|
| Ile różnych wartości przyjmuje kolumna przedmiot? | |
| Ile wierszy zwróci zapytanie SELECT DISTINCT ocena FROM oceny? | |
| Ile wierszy zwróci zapytanie SELECT DISTINCT przedmiot, ocena FROM oceny? | |
| Jakie słowo kluczowe usuwa powtarzające się wiersze z wyniku zapytania? | |
| Zaraz po jakim słowie kluczowym stawia się DISTINCT? | |
| Który operator trzeba wstawić w warunku WHERE ocena ? 5, żeby dostać oceny co najmniej pięć? | |
| Ile wierszy zwróci SELECT DISTINCT uczen FROM oceny WHERE ocena >= 5? | |
| Jaka wartość znajdzie się w pierwszym wierszu SELECT DISTINCT przedmiot FROM oceny ORDER BY przedmiot? |
Gdyby do tabeli dopisać drugi wiersz informatyka, 6 – dokładny duplikat wiersza Zająca – zapytanie bez DISTINCT zwróciłoby wierszy, a to samo zapytanie z DISTINCT nadal tylko , bo duplikat zostaje scalony.
Tak, bo baza musi porównać wiersze między sobą, żeby wykryć powtórzenia. Przy tabelach z zadania maturalnego jest to niezauważalne, ale to powód, dla którego DISTINCT nie dopisuje się „na wszelki wypadek".
Nie. Wynik bywa uporządkowany przy okazji porównywania wierszy, ale nie jest to obiecane – jeśli kolejność ma znaczenie, dopisz ORDER BY.
Wszystkie puste wartości w danej kolumnie uznaje za jedną i zostawia z nich jeden wiersz. To wyjątek od ogólnej zasady, że pustych wartości nie da się ze sobą porównać.
Tak, i to bardzo często razem. DISTINCT usuwa duplikaty, a ORDER BY porządkuje to, co zostało – kolejność w zapytaniu jest stała: najpierw SELECT DISTINCT z listą kolumn, na końcu ORDER BY.
Nie. SELECT DISTINCT(przedmiot), ocena wygląda jak wywołanie funkcji, ale nawiasy po DISTINCT niczego nie zmieniają – DISTINCT nadal obejmuje cały wiersz wyniku, czyli parę przedmiot-ocena.
Nie zawsze – patrz sekcja Porównanie wyżej. Bez funkcji agregującej bywają identyczne, ale GROUP BY dodatkowo pozwala liczyć i filtrować grupy przez HAVING, czego samo DISTINCT nie potrafi.
W standardzie SQL wystarczy COUNT(DISTINCT kolumna). W Accessie ten zapis nie działa – trzeba policzyć wiersze podzapytania, które najpierw samo wybrało unikalne wartości (patrz sekcja Dialekt).
Do tego hasła nie mamy jeszcze przypisanych pojedynczych zadań. Cały spis zadań maturalnych z tego działu jest tutaj:
Zagadnienia z tego samego obszaru matury – warto je powtórzyć razem: