JavaRush /Курси /SQL SELF /Оператори RAISE NOTICE, RETURN QUERY

Оператори RAISE NOTICE, RETURN QUERY

SQL SELF
Рівень 50 , Лекція 3
Відкрита

У програмуванні важливі дві речі: розуміти, що відбувається (особливо коли все йде не так, як ти задумав), і повертати корисні дані. Це особливо актуально для 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;

Це викличе помилку через відсутність другої змінної.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ