Давай глибше розберемося з PL/pgSQL і почнемо юзати його більш активно.
Блок коду
Блок коду в PL/pgSQL — це основний будівельний елемент мови. Можна сказати, це каркас, на якому тримаються наші функції, процедури та інша магія. Блок забезпечує виконання логіки, обробку даних, керування помилками — і все це в одному "контейнері".
PL/pgSQL блоки структуровані і включають три основні частини:
DECLARE: оголошення змінних (опціонально).BEGIN ... END: основний блок виконання, де відбувається вся логіка.EXCEPTION: обробка помилок (опціонально).
Для любителів аналогій: уяви собі рецепт страви. Хоча текст рецепта може починатися зі списку інгредієнтів, основна магія відбувається саме в процесі готування. В термінах PL/pgSQL:
DECLARE— це список інгредієнтів (змінні).BEGIN ... END— це місце, де все змішують, смажать і варять.EXCEPTION— це план дій, якщо щось підгорить.
Синтаксис блоку PL/pgSQL
Спочатку подивимось на загальну структуру блоку, як на "скелет". Потім додамо м'ясо (або вегетаріанський сир, якщо ти таке любиш) — конкретну логіку.
DO $$
DECLARE
-- Тут оголошуються змінні
student_count INT;
BEGIN
-- Тут виконується логіка
SELECT COUNT(*) INTO student_count FROM students;
RAISE NOTICE 'Загальна кількість студентів: %', student_count;
EXCEPTION
-- Тут обробляються помилки
WHEN OTHERS THEN
RAISE NOTICE 'Виникла помилка.';
END;
$$;
Давай розберемо це по кроках.
DECLARE— тут ми оголошуємо наші змінні. Круто, що PL/pgSQL підтримує майже всі типи даних, які є в PostgreSQL — від скромнихINTEGERдо екзотичних JSONB. Щоб оголосити змінну, треба вказати її ім'я, тип даних і, якщо треба, початкове значення.
Приклад:
DECLARE
student_name TEXT; -- Змінна для імені студента
course_count INT := 0; -- Задаємо початкове значення 0
is_graduated BOOLEAN; -- Логічна змінна
Зверни увагу, що змінні можуть бути з ініціалізацією (як course_count) або без.
BEGIN ... END— основний блок виконання.
Ця частина блоку відповідає за виконання основної логіки. Тут можна:
- Виконувати SQL-запити (
SELECT,INSERTі т.д.). - Маніпулювати даними.
- Використовувати керуючі конструкції (
IF,LOOPі т.д.). - Виводити дебажні повідомлення через
RAISE.
Приклад:
BEGIN
SELECT COUNT(*) INTO student_count FROM students;
IF student_count > 0 THEN
RAISE NOTICE 'У нас є студенти!';
ELSE
RAISE NOTICE 'Студентів не знайдено.';
END IF;
END;
EXCEPTION— обробка помилок (опціонально).
Якщо під час виконання блоку виникне помилка, секція EXCEPTION дозволяє перехопити її і зробити щось корисне — наприклад, вивести повідомлення або виконати альтернативний код.
Приклад:
BEGIN
SELECT COUNT(*) INTO student_count FROM non_existing_table; -- Помилка!
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Ой, щось пішло не так!';
END;
Реальний приклад: підрахунок студентів
Тепер зберемо всі частини разом у приклад, який може стати в нагоді в реальному житті. Напишемо блок PL/pgSQL, який рахує кількість студентів у таблиці students і виводить повідомлення.
DO $$
DECLARE
total_students INT; -- Змінна для зберігання кількості студентів
BEGIN
-- Рахуємо кількість студентів
SELECT COUNT(*) INTO total_students FROM students;
-- Виводимо повідомлення з результатом
RAISE NOTICE 'Кількість студентів: %', total_students;
EXCEPTION
-- Обробляємо можливі помилки, наприклад, якщо таблиці не існує
WHEN OTHERS THEN
RAISE NOTICE 'Виникла помилка під час підрахунку студентів.';
END;
$$;
Виклик цього блоку виведе повідомлення в консоль. Наприклад: Кількість студентів: 42.
Особливості використання змінних
Давай розглянемо кілька важливих моментів:
Присвоєння значень змінним. Щоб записати дані у змінну, можна використовувати оператор SELECT INTO:
SELECT COUNT(*) INTO total_students FROM students;
Ініціалізація змінних. Якщо ти не присвоїв значення змінній при оголошенні, її значення за замовчуванням буде NULL.
Наприклад:
DECLARE
my_var INT; -- Значення NULL
Змінні типу RECORD. Це універсальний тип змінної, в яку можна покласти рядок з таблиці. Приклад:
DECLARE
student RECORD;
BEGIN
SELECT * INTO student FROM students WHERE id = 1;
RAISE NOTICE 'Імʼя студента: %, Вік: %', student.name, student.age;
END;
Приклад: підрахунок курсів для студента
Тепер вирішимо практичну задачу: підрахувати, скільки курсів записано за студентом, і вивести результат.
DO $$
DECLARE
student_id INT := 1; -- ID студента
course_count INT; -- Змінна для кількості курсів
BEGIN
-- Рахуємо кількість курсів
SELECT COUNT(*) INTO course_count
FROM enrollments
WHERE student_id = student_id;
-- Виводимо повідомлення
RAISE NOTICE 'Student ID % записаний на % курсів.', student_id, course_count;
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Виникла помилка під час обробки student ID %', student_id;
END;
$$;
Цей блок гнучко працює: можна міняти student_id, щоб перевірити, скільки курсів записано за різними студентами.
Помилки та їх запобігання
Якщо PL/pgSQL всередині тебе вже підстрибує як маленький хот-дог у мікрохвильовці — це нормально. На початку часто можна натрапити на "типові" помилки. Ось кілька прикладів:
Відсутність оголошення змінної. Якщо ти забув оголосити змінну через DECLARE, PL/pgSQL видасть помилку, що змінної "не існує".
Спроба використати NULL як значення. Якщо змінна була оголошена, але їй не присвоєно значення, результатом буде NULL. Це може викликати неочікувану поведінку. Наприклад:
IF my_var = NULL THEN -- НЕ спрацює!
Використовуй IS NULL:
IF my_var IS NULL THEN
Неправильне використання секції EXCEPTION. Іноді програмісти перехоплюють всі помилки (WHEN OTHERS), але не пишуть, що робити. Це може приховати реальну проблему. Краще записувати повідомлення про помилку:
RAISE NOTICE 'Помилка: %', SQLERRM;
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ