CodeGym /Kursy /SQL SELF /Obsługa błędów: RAISE EXCEPTION

Obsługa błędów: RAISE EXCEPTION

SQL SELF
Poziom 52 , Lekcja 0
Dostępny

Wyobraź sobie, że piszesz funkcję, która liczy średnią ocenę studenta. Co się stanie, jeśli spróbujesz podzielić przez zero (na przykład, gdy ocen nie ma)? Wypuścisz taki kod na produkcję — i niespodziewany gość w postaci błędu pojawi się od razu. PL/pgSQL daje ci mocne narzędzia do obsługi takich błędów, dzięki czemu twój kod jest odporny, bezpieczny i przyjemny w użyciu.

Obsługa błędów w PL/pgSQL pozwala na:

  1. Generowanie komunikatów wyjaśniających, co poszło nie tak.
  2. Przerywanie wykonania kodu w przypadku krytycznych błędów.
  3. Logowanie problemów do późniejszej analizy.

Podstawowe poziomy komunikatów PL/pgSQL

PL/pgSQL obsługuje kilka poziomów komunikatów, które pomagają programistom skutecznie diagnozować i rozwiązywać problemy. Oto one:

  • NOTICE: wyświetla informacyjny komunikat. Używane do debugowania.
  • WARNING: powiadomienie o potencjalnym problemie, które nie przerywa działania programu.
  • EXCEPTION: krytyczny błąd, który przerywa działanie programu (i zwraca sterowanie do kodu wywołującego).

Poziomy komunikatów w PL/pgSQL

Poziom komunikatu Opis
NOTICE Informacja lub komunikaty debugowania. Nie wpływa na wykonanie
WARNING Ostrzeżenie o możliwych problemach. Działa jako podpowiedź
EXCEPTION Poważny błąd, który kończy działanie programu

Składnia polecenia RAISE

Do generowania komunikatów i obsługi błędów używa się polecenia RAISE. Oto jego podstawowa składnia:

RAISE <poziom komunikatu> 'treść komunikatu' [, zmienne...];
  • <poziom komunikatu>NOTICE, WARNING, EXCEPTION.
  • 'treść komunikatu' — opis problemu.
  • [zmienne...] — dodatkowe wartości, które można przekazać do treści komunikatu.

Przykład 1: użycie RAISE NOTICE

Czasem ważne jest, żeby wiedzieć, co się dzieje w środku twojej funkcji. Na przykład do debugowania pętli:

DO $$
BEGIN
    FOR i IN 1..5 LOOP
        RAISE NOTICE 'Aktualna wartość i: %', i;
    END LOOP;
END
$$;

Wynik: W konsoli pojawią się linie Aktualna wartość i: 1, Aktualna wartość i: 2 i tak dalej do 5.

Przykład 2: użycie RAISE EXCEPTION

Teraz wyobraź sobie, że piszesz funkcję, która powinna zakończyć się błędem w określonych warunkach:

DO $$
BEGIN
    IF 1 = 1 THEN
        RAISE EXCEPTION 'Coś poszło nie tak!';
    END IF;
END
$$;

Wynik: wykonanie zostaje przerwane, a komunikat błędu pojawia się w konsoli.

Praca z parametrami w RAISE

Używając parametrów, możesz spersonalizować treść komunikatu. Do tego służą placeholdery %:

Przykład 3: wstawianie zmiennych w RAISE

DO $$
DECLARE
    student_name TEXT := 'Ivan';
    average_score NUMERIC := NULL;
BEGIN
    IF average_score IS NULL THEN
        RAISE EXCEPTION 'Student % nie ma średniej oceny!', student_name;
    END IF;
END
$$;

Wynik: komunikat Student Ivan nie ma średniej oceny!.

Jak widzisz, % zostaje zastąpiony przez zmienną student_name, co sprawia, że komunikat jest bardziej czytelny.

Generowanie własnych błędów

Błędy to nie tylko przypadki losowe! Czasem trzeba je generować celowo, żeby zabezpieczyć kod przed złymi danymi.

Przykład 4: sprawdzanie wartości wejściowych

Napiszemy funkcję, która sprawdza wartość liczby i rzuca błąd, jeśli jest ujemna:

CREATE OR REPLACE FUNCTION check_positive(value NUMERIC)
RETURNS TEXT AS $$
BEGIN
    IF value < 0 THEN
        RAISE EXCEPTION 'Liczba % jest ujemna!', value;
    END IF;
    RETURN 'Liczba poprawna.';
END;
$$ LANGUAGE plpgsql;

Teraz przetestujmy funkcję:

SELECT check_positive(-5);

Wynik: komunikat błędu Liczba -5 jest ujemna!.

Jeśli podasz wartość dodatnią:

SELECT check_positive(10);

Wynik: Liczba poprawna.

Obsługa błędów w kontekście

Fajnie, jeśli umiesz generować błędy. Ale jeszcze lepiej — obsługiwać je w zależności od sytuacji. Do tego służy blok BEGIN ... EXCEPTION.

Struktura obsługi błędów

BEGIN
    -- Twój główny kod
EXCEPTION
    WHEN TYP_BŁĘDU THEN
        -- Co zrobić w przypadku tego błędu
    WHEN INNY_BŁĄD THEN
        -- Akcje przy innym błędzie
    WHEN OTHERS THEN
        -- Obsługa wszystkich pozostałych błędów
END;

Rozszyfrujmy składniki:

  • EXCEPTION — słowo kluczowe oznaczające początek bloku obsługi błędów.
  • WHEN — pozwala wskazać konkretny typ obsługiwanego błędu, np. unique_violation lub division_by_zero.
  • OTHERS — używane do obsługi wszystkich błędów, które nie zostały jawnie wymienione w blokach WHEN.

Przykład 5: obsługa dzielenia przez zero

Pokażemy obsługę błędu na prostym przykładzie funkcji dzielenia:

CREATE OR REPLACE FUNCTION safe_divide(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    -- Próbujemy wykonać dzielenie
    RETURN a / b;
EXCEPTION
    WHEN division_by_zero THEN
        RAISE WARNING 'Próba dzielenia przez zero. Zwracam NULL.';
        RETURN NULL;
END;
$$ LANGUAGE plpgsql;

Przetestujmy funkcję:

SELECT safe_divide(10, 2);  -- Oczekiwany wynik: 5
SELECT safe_divide(10, 0);  -- Oczekiwany wynik: NULL i ostrzeżenie w konsoli

Typowe błędy przy użyciu RAISE

Brak poziomu komunikatu. Jeśli zapomnisz podać poziom, PostgreSQL wyrzuci błąd.

Źle:

RAISE 'Komunikat bez poziomu';

Dobrze:

RAISE NOTICE 'Komunikat z poziomem NOTICE';

Nieprawidłowe parametry. Jeśli używasz %, upewnij się, że przekazujesz odpowiednią liczbę zmiennych.

Źle:

RAISE NOTICE 'Przykład z parametrem %';

Dobrze:

RAISE NOTICE 'Przykład z parametrem %', 'wartość';

Przerywanie. Nadmierne użycie RAISE EXCEPTION może przerywać ważne operacje. Używaj go z głową.

Przydatne wskazówki

  1. Uważaj na blok WHEN OTHERS. Jeśli możesz, podawaj konkretne błędy, żeby nie przechwycić błędów, które powinny być obsłużone inaczej.
  2. Używaj RAISE do debugowania. Nigdy nie zostawiaj błędów nieobsłużonych.
  3. Nie zapominaj o wydajności. Obsługa błędów może być kosztowna, szczególnie w dużych procedurach.

Jeśli wszystko zrobisz dobrze, twoje procedury będą odporne i poradzą sobie nawet z niespodziewanymi awariami. PM może być z ciebie bardzo dumny!

2
Zadanie
SQL SELF, poziom 52, lekcja 0
Niedostępne
Obsługa dzielenia przez zero
Obsługa dzielenia przez zero
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION