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;

Это вызовет ошибку из-за отсутствия второй переменной.

2
Задача
SQL SELF, 50 уровень, 3 лекция
Недоступна
Совмещение RAISE NOTICE и RETURN QUERY
Совмещение RAISE NOTICE и RETURN QUERY
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ