Czasem w pętli wszystko idzie zgodnie z planem — aż pojawi się powód, żeby zatrzymać się wcześniej. Na szczęście PL/pgSQL daje nam wygodne narzędzia, żeby tym sterować.
Przerywanie pętli za pomocą EXIT
Czasami trzeba zakończyć pętlę wcześniej, zanim sama dojdzie do końca. Może to być spowodowane np. znalezieniem potrzebnej wartości, wykryciem błędu albo spełnieniem jakiegoś warunku. W takich sytuacjach używamy EXIT.
EXIT to sposób, żeby "powiedzieć" pętli: "Wystarczy, zrobiłeś swoje, czas się zatrzymać".
Składnia EXIT jest mega prosta:
EXIT WHEN warunek;
Tutaj kluczowa fraza WHEN wskazuje, przy jakim warunku pętla zostanie zakończona. Jeśli warunek nie jest podany, EXIT po prostu natychmiast kończy bieżącą pętlę.
Przykład: zakończenie pętli, gdy znaleziono określoną wartość
Załóżmy, że mamy kolumnę z numerami studentów i chcemy znaleźć studenta z konkretnym identyfikatorem. Jak tylko student zostanie znaleziony, pętla powinna się zakończyć.
DO $$
DECLARE
student_id INT;
BEGIN
FOR student_id IN 1..100 LOOP
RAISE NOTICE 'Sprawdzam student ID: %', student_id;
-- Jeśli znaleźliśmy właściwego studenta, kończymy pętlę
IF student_id = 42 THEN
RAISE NOTICE 'Student z ID 42 znaleziony!';
EXIT;
END IF;
END LOOP;
END $$;
W tym przykładzie pętla przechodzi przez liczby od 1 do 100, sprawdzając każdego "studenta". Jak tylko ID 42 zostanie znalezione, pętla wypisuje komunikat i kończy się.
Pomijanie iteracji za pomocą CONTINUE
Są sytuacje, gdy w pętli trzeba pominąć niektóre iteracje, ale kontynuować kolejne. To szczególnie przydatne, jeśli chcesz zignorować "niepotrzebne" dane albo pominąć kroki dla specyficznych warunków.
CONTINUE mówi: "Ok, ten warunek nam nie pasuje, po prostu przechodzimy do następnej iteracji".
CONTINUE działa na tej samej zasadzie co EXIT, tylko zamiast kończyć pętlę, pomija bieżącą iterację:
CONTINUE WHEN warunek;
Jeśli warunek jest spełniony, bieżąca iteracja się kończy i przechodzimy do następnej.
Przykład: pomijanie liczb parzystych
W tym przykładzie będziemy przechodzić przez liczby od 1 do 10, ale ignorować liczby parzyste, wypisując tylko nieparzyste.
DO $$
DECLARE
num INT;
BEGIN
FOR num IN 1..10 LOOP
-- Pomijamy liczby parzyste
IF num % 2 = 0 THEN
CONTINUE;
END IF;
RAISE NOTICE 'Liczba nieparzysta: %', num;
END LOOP;
END $$;
Tutaj CONTINUE pomija wszystkie iteracje, gdzie num % 2 = 0 (czyli liczba jest parzysta). W efekcie w logu pojawią się tylko liczby nieparzyste.
Kombinowanie EXIT i CONTINUE
EXIT i CONTINUE można używać razem, żeby bardziej elastycznie sterować pętlą. Na przykład możesz pomijać niepotrzebne iteracje za pomocą CONTINUE, ale kończyć całą pętlę, jeśli znajdziesz coś ważnego.
Oto przykład, gdzie pomijamy wszystkie liczby podzielne przez 3, ale kończymy pętlę, jak tylko dojdziemy do liczby 15.
DO $$
DECLARE
num INT;
BEGIN
FOR num IN 1..20 LOOP
-- Pomijamy liczby podzielne przez 3
IF num % 3 = 0 THEN
CONTINUE;
END IF;
-- Kończymy pętlę, jeśli liczba to 15
IF num = 15 THEN
RAISE NOTICE 'Zatrzymuję się na liczbie %', num;
EXIT;
END IF;
RAISE NOTICE 'Aktualna liczba: %', num;
END LOOP;
END $$;
Tutaj pętla działa tak:
- Liczby podzielne przez 3 są pomijane (
CONTINUE). - Jeśli liczba to 15, pętla się kończy (
EXIT). - Wszystkie pozostałe liczby są wypisywane.
Bardziej zaawansowany przykład: pomijanie niepoprawnych danych i zakończenie przy krytycznym błędzie
Teraz wyobraźmy sobie bardziej realne zadanie. Chcemy przetworzyć listę studentów, sprawdzając ich dane. Niepoprawne wpisy będziemy pomijać, a w przypadku "krytycznego błędu" przerywać przetwarzanie.
DO $$
DECLARE
student RECORD;
BEGIN
FOR student IN
SELECT * FROM students
LOOP
-- Pomijamy wpisy z niepoprawnymi danymi
IF student.name IS NULL THEN
RAISE NOTICE 'Pomijam studenta z ID %: Brak imienia', student.id;
CONTINUE;
END IF;
-- Kończymy pętlę przy krytycznym błędzie
IF student.status = 'ERROR' THEN
RAISE EXCEPTION 'Krytyczny błąd dla studenta ID %', student.id;
EXIT; -- Ta linia jest właściwie zbędna, bo RAISE EXCEPTION kończy wykonanie.
END IF;
-- Przetwarzanie wpisu
RAISE NOTICE 'Przetwarzam studenta: %', student.name;
END LOOP;
END $$;
W tym przykładzie CONTINUE pomaga pominąć studentów bez imienia, a EXIT (razem z RAISE EXCEPTION) kończy pętlę przy poważnym błędzie.
Praktyczne wskazówki i typowe błędy
Nie zapominaj o logice warunków. Złe użycie wyrażeń warunkowych w EXIT WHEN albo CONTINUE WHEN może prowadzić do nieoczekiwanego zachowania. Na przykład pętla może skończyć się za wcześnie albo pominąć ważne dane.
Nadmierne używanie CONTINUE. Jeśli twój kod jest pełen sprawdzeń z CONTINUE, może warto przemyśleć logikę pętli, żeby była prostsza.
Nie myl EXIT i RETURN. EXIT kończy tylko bieżącą pętlę, a RETURN kończy wykonanie całej funkcji.
Uważaj na nieskończone pętle. Jeśli używasz pętli LOOP bez jasnego warunku zakończenia, zapomnisz o EXIT i twoja pętla może działać w nieskończoność.
GO TO FULL VERSION