Wszystkie zagadnienia: Bazy danych
podstawowy SQLDISTINCTmatura podstawowa z informatyki

DISTINCT – usuwanie duplikatów

Usuwanie powtarzających się wierszy z wyniku zapytania słowem DISTINCT i pułapka porównywania całych wierszy, a nie pojedynczych kolumn.

01

Opis

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.

  • DISTINCT działa na cały wiersz, nie na jedną kolumnę. Dwa wiersze znikają tylko wtedy, gdy są identyczne we wszystkich wypisanych kolumnach.
  • DISTINCT usuwa, ale nie liczy. Do policzenia różnych wartości potrzebna jest funkcja agregująca – samo DISTINCT zwraca tylko listę.
  • Kolumna z unikalnymi wartościami unieważnia DISTINCT. Gdy w SELECT znajdzie się klucz główny albo inna kolumna bez powtórzeń, każdy wiersz staje się z definicji różny i nic nie zostaje usunięte.
  • Dwa puste pola liczą się jako ta sama wartość. To jedyne miejsce, w którym NULL zachowuje się jak zwykła wartość, a nie jak nieznana.
02

Zapytanie

-- Bez DISTINCT: przedmiot powtarza się tyle razy, ile jest z niego ocen
SELECT przedmiot
FROM oceny
Wynik zapytania
przedmiot
informatyka
matematyka
informatyka
informatyka
matematyka
-- Z DISTINCT: sama lista przedmiotów
SELECT DISTINCT przedmiot
FROM oceny
Wynik zapytania
przedmiot
informatyka
matematyka
-- DISTINCT patrzy na cały wiersz - tu na pary przedmiot + ocena
SELECT DISTINCT przedmiot, ocena
FROM oceny
Wynik zapytania
przedmiotocena
informatyka5
matematyka4
informatyka3
informatyka6
matematyka5
-- DISTINCT na prawdziwej tabeli uczniowie: klasy powtarzają się mimo różnych uczniów
SELECT DISTINCT klasa
FROM uczniowie
Wynik zapytania
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
Wynik zapytania
klasa
(brak wierszy)
03

Dialekt

W AccessieStandardowy SQLZnaczenie
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
04

Porównanie

CechaDISTINCTGROUP BY
Co robiusuwa powtarzające się wiersze z gotowego wynikudzieli wiersze na grupy według wartości wskazanych kolumn
Można liczyć wewnątrznie – bez dodatkowego podzapytania nie policzy liczby gruptak – naturalnie łączy się z funkcją agregującą (COUNT, SUM, AVG) na każdą grupę
Wynik bez funkcji agregującejlista unikalnych wierszypodobna lista unikalnych grup – wyniki obu bywają wtedy identyczne
Filtrowanie wyniku po wyliczonej wartościniemożliwe – DISTINCT nic nie liczyHAVING 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
05

Typowe błędy

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.

06

Zapamiętaj

  • DISTINCT usuwa z wyniku powtarzające się wiersze, porównując wszystkie wypisane kolumny naraz.
  • Stoi zawsze zaraz po SELECT, przed pierwszą kolumną listy.
  • Dopisanie kolumny z unikalnymi wartościami (np. klucza głównego) sprawia, że DISTINCT przestaje cokolwiek usuwać.
  • DISTINCT nie liczy – do zliczenia różnych wartości potrzebna jest funkcja agregująca, najlepiej razem z GROUP BY.
  • W Accessie nie da się napisać Count(DISTINCT kolumna) – trzeba to obejść podzapytaniem.
  • Dwa puste pola (NULL) DISTINCT traktuje jak tę samą wartość i zostawia z nich jeden wiersz.
  • W zadaniach z Informatora CKE brak DISTINCT przy poleceniu „bez powtórzeń" kosztuje realny punkt, nawet gdy reszta zapytania jest poprawna.
07

Sprawdź się

Fragment tabeli oceny (te same dane co w przykładach wyżej, z dopisaną kolumną ucznia):

uczenprzedmiotocena
Kowalskainformatyka5
Nowakmatematyka4
Wiśniewskiinformatyka3
Zającinformatyka6
Dąbrowskimatematyka5

Uzupełnij odpowiedzi na podstawie tabeli oceny:

PytanieOdpowiedź
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.

08

Najczęściej zadawane pytania

Czy DISTINCT spowalnia zapytanie?

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".

Czy DISTINCT sortuje wynik?

Nie. Wynik bywa uporządkowany przy okazji porównywania wierszy, ale nie jest to obiecane – jeśli kolejność ma znaczenie, dopisz ORDER BY.

Jak DISTINCT traktuje puste wartości?

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ć.

Czy DISTINCT można łączyć z ORDER BY?

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.

Czy da się zastosować DISTINCT tylko do jednej kolumny z kilku wybranych?

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.

Czy DISTINCT i GROUP BY zawsze dają ten sam wynik?

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.

Jak policzyć, ile jest różnych wartości w kolumnie?

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).

Przećwicz w zadaniach maturalnych

Do tego hasła nie mamy jeszcze przypisanych pojedynczych zadań. Cały spis zadań maturalnych z tego działu jest tutaj:

Zadania z działu: SQL

↗

Powiązane zagadnienia