Bazy danych Oracle – ROWNUM i problemy

O czym?
Jak wybrać n rekordów z tabeli, czyli do czego można użyć ROWNUM. W tym poście pokażę również na jakie problemy możemy napotkać korzystając z ROWNUM.

ROWNUM
Pseudokolumna ROWNUM służy do numerowania rekordów w wyniku działania zapytania – jej wartość rośnie o 1 dla każdego wiersza zwróconego w procesie selekcji rekordów.

SELECT ROWNUM, e.* FROM employees e;

Powyższy przykład powoduje wyświetlenie wszystkich kolumn z tabeli employees. Jako pierwsze zostanie wyświetlona pseudokolumna ROWNUM, która ponumeruje rekordy oraz wyświetlone zostaną pozostałe kolumny z tabeli employees.

W celu wyświetlenia 5 rekordów z tabeli należy użyć warunku WHERE.

SELECT ROWNUM, e.* FROM employees e
WHERE ROWNUM<=5;

Powyższy przykład spowoduje wyświetlenie 5 pierwszych rekordów zwróconych przez zapytanie:

SELECT ROWNUM, e.* FROM employees e;

Problemy z ROWNUM

Skoro nie mamy ORDER BY nie wiemy w jakiej kolejności rekordy zostaną wyświetlone. Dodajmy zatem ORDER BY do zapytania, w którym znajduje się ROWNUM:

SELECT ROWNUM, e.* FROM employees e
ORDER BY last_name, first_name;

Okazuje się, że rekordy są posortowane z naszym życzeniem – niestety w kolumnie ROWNUM wartości nie są uporządkowane. Dlaczego? Najpierw nastąpiło przypisanie wartości w ROWNUM dla kolejnych rekordów, a dopiero później sortowanie. Możliwe jest obejście tego problemu przy użyciu mechanizmu podzapytań.

Czy to koniec problemów z ROWNUM? Otóż nie. Spróbujmy wybrać drugi rekord z tabeli employees (pomijając „problematyczny” ORDER BY):

SELECT ROWNUM, e.* FROM employees e
WHERE ROWNUM=2;

Czemu zapytanie nie wybiera rekordów skoro jeszcze przed chwilą zwracało ich zdecydowanie więcej niż 2? Najpierw następuje przypisanie ROWNUM i sprawdzany jest warunek – czyli dla pierwszego rekordu sprawdzany jest WHERE ROWNUM 1=2. Prawda? Nie. Rekord odrzucamy.

Dla drugiego rekordu zostaje przypisana wartość ROWNUM. Jaka? Otóż wartość 1 – ponieważ poprzedni rekord został odrzucony – jest to pierwszy rekord, który może być w wyniku działania zapytania. Sprawdzamy zatem znany nam warunek WHERE ROWNUM 1=2. Prawda? Nie. Rekord odrzucamy. Itd. Itd. Ten problem można obejść również wykorzystując podzapytania.

Z tej samej przyczyny zapytania WHERE ROWNUM>liczba nie będą wyświetlały rekordów.

Czy w takim wypadku poniższe zapytanie wyświetli rekord/rekordy:

SELECT ROWNUM,e.* FROM employees e
WHERE ROWNUM=1;

Wyświetli 1 rekord, ponieważ spełniony będzie warunek WHERE 1=1. Każdy kolejny rekord(kandydat do wyświetlenia) nie zostanie wyświetlony, ponieważ warunek postać WHERE 2=1 (dla drugiego rekordu i każdego kolejnego).

Wnioski:

– Limitowanie działa poprawnie tylko bez wykorzystania klauzuli ORDER BY
– Limitowanie rekordów z wykorzystaniem ROWNUM z użyciem operatora równości jest problematyczne

Rozwiązanie tych problemów przy pomocy podzapytań przedstawię w kolejnym wpisie.

About Rafal Stryjek

My LinkedIn profile. Passionate about data. Data Warehousing Expert. Snowflake Data SuperHero & Oracle ACE Associate. International conferences Speaker: Snowflake Build Summit-BUILD.local 2021, Oracle Open World, DOAG, UKOUG, APEX World,.. Visit dataconsulting.pl website!
This entry was posted in Oracle SQL Podstawy and tagged , , . Bookmark the permalink.

Leave a Reply