Ograniczanie liczby wierszy wyniku klauzulą TOP w Accessie i LIMIT w innych bazach – składnia, TOP n PERCENT oraz zachowanie przy remisach na granicy limitu.
Polecenia typu „podaj trzech najlepszych uczniów" albo „wypisz pięć najdroższych produktów" wymagają dwóch rzeczy naraz: uporządkowania wyniku i obcięcia go do kilku pierwszych wierszy. Pierwsze robi ORDER BY, drugie – klauzula ograniczająca liczbę wierszy.
Bez sortowania to nie ma sensu. „Trzy pierwsze wiersze" nieuporządkowanego wyniku to trzy przypadkowe wiersze, bo kolejność bez ORDER BY nie jest określona. Te dwie klauzule chodzą w parze i użycie jednej bez drugiej jest niemal zawsze błędem.
Access używa TOP, wstawianego zaraz po SELECT, przed listą kolumn. Liczba po TOP musi być całkowita. Dopisanie słowa PERCENT zmienia znaczenie z „tylu wierszy" na „tyle procent wszystkich wierszy".
Większość pozostałych baz używa LIMIT – dopisywanego na samym końcu zapytania, za ORDER BY. Efekt jest ten sam, miejsce w zapytaniu i słowo kluczowe – inne.
Najważniejsza różnica w zachowaniu: TOP nie rozstrzyga remisów. Jeśli poprosisz o trzy wiersze, a trzeci i czwarty mają w kolumnie sortowania identyczną wartość, Access zwróci cztery wiersze – wszystkie remisujące. Nie potrafi arbitralnie wybrać jednego z równych sobie, więc woli oddać komplet. LIMIT zachowuje się odwrotnie: zwróci dokładnie tyle wierszy, ile poprosiłeś, ucinając remis w przypadkowym miejscu.
To znaczy, że zapytanie z TOP 3 może zwrócić więcej niż 3 wiersze – i nie jest to błąd, tylko udokumentowane zachowanie. Jeśli musisz mieć dokładnie trzy, trzeba dołożyć do ORDER BY drugą kolumnę, która remisy rozstrzygnie.
-- Trzej uczniowie z najwyższą średnią (zapis Accessa) SELECT TOP 3 nazwisko, srednia FROM uczniowie ORDER BY srednia DESC
| nazwisko | srednia |
|---|---|
| Wiśniewski | 5.10 |
| Kowalska | 4.75 |
| Dąbrowski | 4.10 |
-- To samo w bazach używających LIMIT - klauzula idzie na koniec SELECT nazwisko, srednia FROM uczniowie ORDER BY srednia DESC LIMIT 3
| nazwisko | srednia |
|---|---|
| Wiśniewski | 5.10 |
| Kowalska | 4.75 |
| Dąbrowski | 4.10 |
-- Uczeń z najniższą średnią: to samo TOP, odwrotny kierunek sortowania SELECT TOP 1 nazwisko, srednia FROM uczniowie ORDER BY srednia
| nazwisko | srednia |
|---|---|
| Nowak | 3.20 |
-- Procent zamiast liczby wierszy: 40% z pięciu uczniów to równo dwa wiersze SELECT TOP 40 PERCENT nazwisko, srednia FROM uczniowie ORDER BY srednia
| nazwisko | srednia |
|---|---|
| Nowak | 3.20 |
| Zając | 3.90 |
-- Remis na granicy TOP: trzeci i czwarty wiersz mają tę samą klasę SELECT TOP 3 nazwisko, klasa FROM uczniowie ORDER BY klasa
| nazwisko | klasa |
|---|---|
| Kowalska | 3A |
| Wiśniewski | 3A |
| Nowak | 3B |
| Dąbrowski | 3B |
-- Bez ORDER BY: kolejność wiersza nie jest niczym gwarantowana SELECT TOP 3 nazwisko FROM uczniowie
| nazwisko |
|---|
| Kowalska |
| Nowak |
| Wiśniewski |
Dwa ostatnie zapytania z sekcji wyżej wyglądają na błędne, a są poprawne – warto wiedzieć dlaczego.
Zapytanie z remisem zwraca cztery wiersze zamiast trzech. Po posortowaniu po klasie trzeci i czwarty wiersz mają tę samą wartość „3B", a dokumentacja Accessa mówi wprost, że TOP nie rozstrzyga remisów: jeśli wartość na granicy powtarza się, do wyniku wchodzą wszystkie wiersze z tą wartością. Kolejność w obrębie jednej klasy (Kowalska czy Wiśniewski jako pierwsza) też nie jest niczym ustalona – decyduje o niej dopiero druga kolumna w ORDER BY.
Ostatnie zapytanie jest celowym antywzorcem. Bez ORDER BY pokazany wynik to tylko jedna z możliwych odpowiedzi: dokumentacja Accessa nazywa to „dowolnym zbiorem" wierszy spełniających warunek, więc baza może zwrócić te same trzy wiersze w innej kolejności albo zupełnie inne trzy z pięciu. To nie jest błąd bazy, tylko konsekwencja braku sortowania.
Procent, który nie dzieli się równo. W przykładzie wyżej 40% z pięciu wierszy to dokładnie dwa. Gdyby procent wypadł „w połowie wiersza" (np. 50% z pięciu), liczba zwróconych wierszy zależy od tego, jak Access zaokrągli wynik – dokumentacja tego nie rozstrzyga. Przy zadaniu z procentem sprawdź to w swoim Accessie, zamiast zakładać zaokrąglenie w górę.
| W Accessie | Standardowy SQL | Znaczenie |
|---|---|---|
SELECT TOP 3 ... |
... LIMIT 3 |
trzy pierwsze wiersze wyniku |
SELECT TOP 10 PERCENT ... |
(brak prostego odpowiednika) |
pierwsze 10% wierszy |
(zwraca remisujące) |
(ucina dokładnie) |
zachowanie przy równych wartościach |
TOP bez ORDER BY. SELECT TOP 3 nazwisko FROM uczniowie jest poprawne składniowo i baza je wykona – tylko że nie wiadomo, które trzy wiersze wybierze ani w jakiej kolejności. To nie jest błąd, który Access zgłosi, tylko cichy błąd logiczny: zapytanie „ma sens", dopóki nikt nie porówna wyniku z oczekiwanym. Naprawa to zawsze dopisanie ORDER BY po kolumnie, która faktycznie decyduje o kolejności.
Oczekiwanie dokładnie tylu wierszy, ile podano po TOP. SELECT TOP 3 nazwisko FROM uczniowie ORDER BY klasa zwraca cztery wiersze, nie trzy, bo trzeci i czwarty mają tę samą klasę. Wielu uczniów uznaje to za błąd bazy i próbuje „naprawić" zapytanie, choć to zgodne z dokumentacją zachowanie Accessa przy remisie. Jeśli liczba wierszy musi być dokładna, trzeba dołożyć drugą kolumnę do ORDER BY, np. nazwisko alfabetycznie.
PERCENT pomylony z liczbą wierszy. SELECT TOP 50 PERCENT nazwisko FROM uczniowie nie zwraca 50 wierszy – zwraca połowę wierszy tabeli (a gdy połowa nie wypada równo, liczbę wierszy rozstrzyga zaokrąglenie po stronie Accessa). Pominięcie słowa PERCENT przy pisaniu zapytania „na pamięć" to najczęstsza literówka w tej klauzuli, a skutek jest odwrotny do zamierzonego: zamiast procentu dostajemy sztywną liczbę wierszy.
TOP wstawiony na końcu zapytania, jak LIMIT. SELECT nazwisko FROM uczniowie ORDER BY srednia DESC TOP 3 zgłosi błąd składni w Accessie. TOP musi stać bezpośrednio po SELECT, przed listą kolumn – w przeciwieństwie do LIMIT, które faktycznie idzie na sam koniec zapytania. Przenoszenie nawyku z jednego dialektu do drugiego jest tu odwrotnością sensownego zapisu.
LIMIT z PERCENT. SELECT nazwisko FROM uczniowie ORDER BY srednia DESC LIMIT 50 PERCENT w bazie posługującej się LIMIT zwróci błąd składni. LIMIT przyjmuje wyłącznie liczbę wierszy (ewentualnie z przesunięciem OFFSET), nie ma odpowiednika PERCENT – to jedna z sytuacji bez prostego przeniesienia zapisu między dialektami.
Brak DESC przy szukaniu największej wartości. SELECT TOP 1 nazwisko FROM uczniowie ORDER BY srednia zwraca ucznia z najniższą średnią, nie najwyższą, bo domyślny kierunek sortowania jest rosnący. To błąd, który nie objawia się żadnym komunikatem – zapytanie wykonuje się poprawnie i zwraca jeden wiersz, tylko nie ten, o który chodziło w poleceniu. Kierunek sortowania zawsze decyduje ORDER BY, TOP samo w sobie nie „wie", czy ma zwrócić największe, czy najmniejsze wartości.
Fragment tabeli produkty w sklepie internetowym:
| produkt | cena |
|---|---|
| dysk SSD | 349 |
| klawiatura | 199 |
| mysz | 79 |
| monitor | 899 |
| słuchawki | 199 |
Uzupełnij odpowiedzi na podstawie tabeli produkty:
| Pytanie | Odpowiedź |
|---|---|
Ile wierszy zwróci SELECT TOP 2 produkt FROM produkty ORDER BY cena DESC? | |
| Który produkt znajdzie się na pierwszym miejscu tego wyniku? | |
Ile wierszy naprawdę zwróci SELECT TOP 3 produkt FROM produkty ORDER BY cena DESC w Accessie? | |
| Który produkt ma tę samą cenę co klawiatura i przez to tworzy remis na granicy? | |
| Jakiego słowa kluczowego użyje MySQL zamiast TOP? | |
| W którym miejscu zapytania stoi to słowo kluczowe? | |
Ile wierszy zwróci SELECT TOP 40 PERCENT produkt FROM produkty ORDER BY cena DESC przy 5 wierszach w tabeli? | |
| Które słowo dopisane po TOP zamienia jednostkę z liczby wierszy na procent całości? |
Powodem, dla którego trzecie pytanie w tabeli nie ma odpowiedzi „3", jest na granicy limitu – Access woli oddać komplet wierszy o równej cenie niż wybrać jeden z nich po swojemu. Bez klauzuli żadne z powyższych zapytań nie miałoby zresztą sensu, bo kolejność wierszy w tabeli produkty nie byłaby niczym określona.
Składniowo tak, ale wynik jest bezużyteczny – dostaniesz kilka przypadkowych wierszy. Traktuj TOP bez ORDER BY jako sygnał, że w zapytaniu czegoś brakuje.
Tak, choć trudno wskazać sensowne zastosowanie. Wartość po TOP musi być liczbą całkowitą – ułamek zostanie odrzucony jako błąd składni.
W Accessie nie ma na to prostego zapisu i trzeba się posiłkować podzapytaniem. Bazy z LIMIT mają do tego dodatkowy parametr przesunięcia (OFFSET), który pozwala pominąć zadaną liczbę początkowych wierszy.
Tak, ale kolejność w zapytaniu ma znaczenie: Access najpierw usuwa duplikaty, dopiero potem obcina wynik do podanej liczby wierszy. Samo działanie DISTINCT omawia osobne hasło.
W standardowym zapisie – nie, po TOP musi stać stała liczbowa, nie kolumna ani wynik obliczenia. Jeśli granica ma zależeć od danych (np. „tyle wierszy, ile wynosi pewna wartość"), trzeba się posłużyć parametrem zapytania, a nie zwykłą stałą wpisaną wprost w treść polecenia.
Access zaokrągla liczbę wierszy do najbliższej liczby całkowitej, więc przy nieparzystej liczbie wierszy w tabeli wynik częściej wychodzi w górę niż w dół. Przy wątpliwościach bezpieczniej jest policzyć to samodzielnie na konkretnej liczbie wierszy tabeli, zamiast zgadywać.
Nie – Access rozpoznaje wyłącznie TOP, słowo LIMIT zgłosi błąd składni. Zamiana działa tylko w jedną stronę myślenia: znając zasadę „TOP po SELECT, LIMIT na końcu", łatwiej przenieść zapytanie do dokumentacji innej bazy, ale w samym Accessie działa tylko jego własna składnia.
Nie wprost – TOP obcina dopiero gotowy, już posortowany wynik całego zapytania, a nie wiersze wejściowe przed grupowaniem. Żeby ograniczyć liczbę zwracanych grup, TOP i ORDER BY muszą dotyczyć kolumny z wartością zagregowaną, a nie surowej tabeli – mechanikę samego grupowania opisuje hasło GROUP BY.
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: