Wejdźmy głębiej w PL/pgSQL i zacznijmy korzystać z niego bardziej na serio.
Blok kodu
Blok kodu w PL/pgSQL to taki główny klocek budulcowy języka. Można powiedzieć, że to szkielet, na którym wiszą nasze funkcje, procedury i cała ta magia. Blok ogarnia wykonywanie logiki, przetwarzanie danych, obsługę błędów – wszystko w jednym "kontenerze".
Bloki PL/pgSQL są uporządkowane i mają trzy główne części:
DECLARE: deklaracja zmiennych (opcjonalnie).BEGIN ... END: główny blok wykonania, gdzie dzieje się cała logika.EXCEPTION: obsługa błędów (opcjonalnie).
Dla fanów analogii: wyobraź sobie przepis na danie. Chociaż tekst przepisu może zaczynać się od listy składników, cała magia dzieje się podczas gotowania. W PL/pgSQL:
DECLARE— to lista składników (zmienne).BEGIN ... END— tu się miesza, smaży i gotuje.EXCEPTION— to plan awaryjny, jak coś się przypali.
Składnia bloku PL/pgSQL
Najpierw zobaczmy ogólną strukturę bloku, taki "szkielet". Potem dorzucimy mięso (albo wege ser, jak wolisz) – konkretną logikę.
DO $$
DECLARE
-- Tutaj deklarujemy zmienne
student_count INT;
BEGIN
-- Tutaj wykonujemy logikę
SELECT COUNT(*) INTO student_count FROM students;
RAISE NOTICE 'Całkowita liczba studentów: %', student_count;
EXCEPTION
-- Tutaj obsługujemy błędy
WHEN OTHERS THEN
RAISE NOTICE 'Wystąpił błąd.';
END;
$$;
Rozłóżmy to na części pierwsze.
DECLARE— tutaj deklarujemy nasze zmienne. Fajne jest to, że PL/pgSQL obsługuje prawie wszystkie typy danych dostępne w PostgreSQL – od zwykłegoINTEGERpo egzotyczne JSONB. Żeby zadeklarować zmienną, podajesz jej nazwę, typ danych i, jeśli chcesz, wartość początkową.
Przykład:
DECLARE
student_name TEXT; -- Zmienna na imię studenta
course_count INT := 0; -- Ustawiamy początkową wartość na 0
is_graduated BOOLEAN; -- Zmienna logiczna
Zwróć uwagę, że zmienne mogą być z inicjalizacją (jak course_count) albo bez.
BEGIN ... END— główny blok wykonania.
Ta część bloku odpowiada za całą logikę. Tutaj możesz:
- Wykonywać zapytania SQL (
SELECT,INSERT, itd.). - Manipulować danymi.
- Używać konstrukcji sterujących (
IF,LOOP, itd.). - Wyświetlać komunikaty debugowe przez
RAISE.
Przykład:
BEGIN
SELECT COUNT(*) INTO student_count FROM students;
IF student_count > 0 THEN
RAISE NOTICE 'Mamy studentów!';
ELSE
RAISE NOTICE 'Nie znaleziono studentów.';
END IF;
END;
EXCEPTION— obsługa błędów (opcjonalnie).
Jeśli podczas wykonywania bloku pojawi się błąd, sekcja EXCEPTION pozwala go przechwycić i zrobić coś sensownego – np. wyświetlić komunikat albo wykonać alternatywny kod.
Przykład:
BEGIN
SELECT COUNT(*) INTO student_count FROM non_existing_table; -- Błąd!
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Ups, coś poszło nie tak!';
END;
Prawdziwy przykład: liczenie studentów
Teraz złóżmy wszystko w całość na przykładzie, który może się przydać w realu. Napiszemy blok PL/pgSQL, który liczy liczbę studentów w tabeli students i wyświetla komunikat.
DO $$
DECLARE
total_students INT; -- Zmienna do przechowywania liczby studentów
BEGIN
-- Liczymy liczbę studentów
SELECT COUNT(*) INTO total_students FROM students;
-- Wyświetlamy komunikat z wynikiem
RAISE NOTICE 'Liczba studentów: %', total_students;
EXCEPTION
-- Obsługujemy możliwe błędy, np. jeśli tabela nie istnieje
WHEN OTHERS THEN
RAISE NOTICE 'Wystąpił błąd podczas liczenia studentów.';
END;
$$;
Wywołanie tego bloku wyświetli komunikat w konsoli. Na przykład: Liczba studentów: 42.
Szczegóły używania zmiennych
Ogarniemy kilka ważnych rzeczy:
Przypisywanie wartości do zmiennych. Żeby wrzucić dane do zmiennej, użyj operatora SELECT INTO:
SELECT COUNT(*) INTO total_students FROM students;
Inicjalizacja zmiennych. Jeśli nie przypiszesz wartości zmiennej przy deklaracji, jej wartość domyślna to NULL.
Na przykład:
DECLARE
my_var INT; -- Wartość to NULL
Zmienne typu RECORD. To uniwersalny typ zmiennej, do której można wrzucać wiersze z tabeli. Przykład:
DECLARE
student RECORD;
BEGIN
SELECT * INTO student FROM students WHERE id = 1;
RAISE NOTICE 'Imię studenta: %, Wiek: %', student.name, student.age;
END;
Przykład: liczenie kursów dla studenta
Teraz rozwiążemy praktyczny problem: policzymy, ile kursów ma zapisanych student i wyświetlimy wynik.
DO $$
DECLARE
student_id INT := 1; -- ID studenta
course_count INT; -- Zmienna na liczbę kursów
BEGIN
-- Liczymy liczbę kursów
SELECT COUNT(*) INTO course_count
FROM enrollments
WHERE student_id = student_id;
-- Wyświetlamy komunikat
RAISE NOTICE 'Student ID % jest zapisany na % kursów.', student_id, course_count;
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Wystąpił błąd podczas przetwarzania studenta ID %', student_id;
END;
$$;
Ten blok jest elastyczny: możesz zmieniać student_id, żeby sprawdzić, ile kursów mają różni studenci.
Błędy i jak ich unikać
Jeśli PL/pgSQL w Tobie już się gotuje jak hot-dog w mikrofalówce, to normalne. Na początku łatwo trafić na "typowe" błędy. Oto kilka przykładów:
Brak deklaracji zmiennej. Jeśli zapomnisz zadeklarować zmienną przez DECLARE, PL/pgSQL wywali błąd, że zmienna "nie istnieje".
Próba użycia NULL jako wartości. Jeśli zmienna została zadeklarowana, ale nie dostała wartości, jej wartość to NULL. To może powodować dziwne zachowania. Na przykład:
IF my_var = NULL THEN -- NIE zadziała!
Użyj IS NULL:
IF my_var IS NULL THEN
Złe użycie sekcji EXCEPTION. Czasem programiści łapią wszystkie błędy (WHEN OTHERS), ale nie piszą, co zrobić. To może ukryć prawdziwy problem. Lepiej wypisać komunikat o błędzie:
RAISE NOTICE 'Błąd: %', SQLERRM;
GO TO FULL VERSION