У програмуванні важливі дві речі: розуміти, що відбувається (особливо коли все йде не так, як ти задумав), і повертати корисні дані. Це особливо актуально для PL/pgSQL, бо робота йде на стороні сервера, а значить дебажити — не завжди просто. Тут виручають вбудовані інструменти:
RAISE NOTICE — це спосіб виводити повідомлення під час виконання функції. Уяви його як console.log у JavaScript або print у Python. Можеш показати значення змінних, поточний стан виконання або просто залишити "привітання" для майбутнього себе.
RETURN QUERY — це спосіб повернути набір даних, наприклад цілу таблицю або результат складного запиту. З ним PL/pgSQL-функції стають схожими на повноцінні SQL-запити.
Команда RAISE NOTICE
RAISE NOTICE дозволяє виводити повідомлення на екран у процесі виконання функції. Формат виглядає так:
RAISE NOTICE 'Повідомлення: %', значення;
%— це плейсхолдер для змінної, схожий наprintfу C.- Після тексту повідомлення можна перелічити змінні, які треба підставити.
Приклад використання
Уяви, що ти пишеш функцію, яка рахує кількість студентів у різних групах. Хочеш бачити проміжні значення, щоб зрозуміти, чи все йде по плану.
CREATE OR REPLACE FUNCTION count_students_in_groups() RETURNS VOID AS $$
DECLARE
group_name TEXT;
student_count INT;
BEGIN
FOR group_name IN SELECT DISTINCT group_name FROM students LOOP
SELECT COUNT(*) INTO student_count
FROM students WHERE group_name = group_name;
-- Вивід результатів
RAISE NOTICE 'Група: %, Кількість студентів: %', group_name, student_count;
END LOOP;
END;
$$ LANGUAGE plpgsql;
Коли ти викличеш цю функцію:
SELECT count_students_in_groups();
Побачиш такі повідомлення в логах:
NOTICE: Група: Математика, Кількість студентів: 30
NOTICE: Група: Філософія, Кількість студентів: 25
NOTICE: Група: Біологія, Кількість студентів: 18
Зверни увагу, що функція нічого не повертає (вона створена з RETURNS VOID), але RAISE NOTICE показує, як іде цикл.
Корисні трюки з RAISE
Окрім NOTICE, можна юзати й інші рівні повідомлень:
RAISE DEBUG— для додаткової інфи (відображається, тільки якщо виставлений рівень логування DEBUG).RAISE INFO— для загальної інфи.RAISE WARNING— для попереджень.RAISE EXCEPTION— для генерації помилок, це розглянемо пізніше.
Для дебагу краще юзати NOTICE або DEBUG, бо вони зручні і не зупиняють виконання функції.
Команда RETURN QUERY: повертай дані, як профі
RETURN QUERY використовується в PL/pgSQL для повернення набору рядків. З ним можна повернути результат SQL-запиту прямо з функції. Синтаксис такий:
RETURN QUERY <SQL-запит>;
Також можна комбінувати кілька запитів:
RETURN QUERY <SQL-запит 1>;
RETURN QUERY <SQL-запит 2>;
Приклад 1: функція з RETURN QUERY
Напишемо функцію, яка повертає список студентів із заданої групи.
CREATE OR REPLACE FUNCTION get_students_by_group(group_name TEXT)
RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, name
FROM students
WHERE group_name = group_name;
END;
$$ LANGUAGE plpgsql;
Тепер викликаємо цю функцію:
SELECT * FROM get_students_by_group('Математика');
Щоб перевірити роботу функції, спочатку створи таблицю students і додай у неї дані:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
group_name TEXT NOT NULL
);
INSERT INTO students (name, group_name) VALUES
('Otto Song', 'Фізика'),
('Alex Lin', 'Математика'),
('Anna Vel', 'Математика'),
('Maria Chi', 'Історія');
Результат:
| id | name |
|---|---|
| 2 | Alex Lin |
| 3 | Anna Vel |
Як бачиш, функція працює як звичайний SQL-запит.
Приклад 2: Комбінування кількох запитів
А якщо треба повернути об'єднані дані з кількох таблиць? Давай повернемо список студентів і курсів, на які вони записані.
CREATE OR REPLACE FUNCTION get_students_and_courses()
RETURNS TABLE(student_name TEXT, course_name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT s.name, c.name
FROM students s
JOIN enrollments e ON s.id = e.student_id
JOIN courses c ON e.course_id = c.id;
END;
$$ LANGUAGE plpgsql;
Для початку створи три таблиці: students, courses і enrollments, а потім додай трохи даних:
-- Таблиця студентів
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Таблиця курсів
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Таблиця записів на курси (зв'язуюча)
CREATE TABLE enrollments (
student_id INT REFERENCES students(id),
course_id INT REFERENCES courses(id)
);
-- Додаємо студентів
INSERT INTO students (name) VALUES
('Otto Song'),
('Alex Lin'),
('Anna Vel'),
('Maria Chi');
-- Додаємо курси
INSERT INTO courses (name) VALUES
('Математика'),
('Фізика'),
('Історія');
-- Додаємо записи на курси
INSERT INTO enrollments (student_id, course_id) VALUES
(1, 2), -- Otto -> Фізика
(2, 1), -- Alex -> Математика
(3, 1), -- Anna -> Математика
(4, 3); -- Maria -> Історія
У цьому випадку виклик функції:
SELECT * FROM get_students_and_courses();
дасть такий результат:
| student_name | course_name |
|---|---|
| Otto Song | Фізика |
| Alex Lin | Математика |
| Anna Vel | Математика |
| Maria Chi | Історія |
Функція акуратно об'єднує дані з трьох таблиць і показує, хто зі студентів на який курс записаний.
Комбінування RAISE NOTICE і RETURN QUERY
Іноді RETURN QUERY і RAISE NOTICE можуть працювати в одній функції, щоб ти міг контролювати виконання функції і бачити проміжні результати.
Ось приклад функції, яка повертає дані про студентів і одночасно виводить повідомлення, щоб показати хід виконання:
CREATE OR REPLACE FUNCTION debug_students()
RETURNS TABLE(student_id INT, student_name TEXT) AS $$
DECLARE
count_students INT;
BEGIN
-- Рахуємо кількість студентів
SELECT COUNT(*) INTO count_students FROM students;
RAISE NOTICE 'Всього студентів: %', count_students;
-- Повертаємо дані про студентів
RETURN QUERY
SELECT id, name FROM students;
RAISE NOTICE 'Функція завершила виконання.';
END;
$$ LANGUAGE plpgsql;
Якщо таблиця students ще не створена, додай її і внеси дані:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
INSERT INTO students (name) VALUES
('Otto Song'),
('Alex Lin'),
('Anna Vel'),
('Maria Chi');
Тепер, викликавши функцію:
SELECT * FROM debug_students();
Ти отримаєш у виводі і дані, і повідомлення:
| student_id | student_name |
|---|---|
| 1 | Otto Song |
| 2 | Alex Lin |
| 3 | Anna Vel |
| 4 | Maria Chi |
Вивід повідомлення в консоль:
NOTICE: Всього студентів: 4
NOTICE: Функція завершила виконання.
Типові помилки при використанні
Помилка зі змінними в RAISE NOTICE: якщо ти забув оголосити змінну або зробив помилку в її імені, отримаєш помилку variable does not exist. Завжди перевіряй, що змінні оголошені коректно.
Помилка з типом повернення: якщо ти юзаєш RETURN QUERY, але не вказуєш RETURNS TABLE при створенні функції, PostgreSQL видасть помилку. Переконайся, що типи повернення збігаються з повертаємими даними.
Помилка з плейсхолдерами в RAISE: якщо кількість плейсхолдерів % не відповідає кількості змінних, з'явиться помилка. Наприклад:
RAISE NOTICE 'Значення: %, %', value1;
Це викличе помилку через відсутність другої змінної.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ