Ошибка «отношение new не существует» в триггере PostgreSQL: причины и исправление
При создании триггерных функций в PostgreSQL разработчики часто сталкиваются с ошибкой ERROR: отношение «new» не существует. Это происходит, когда внутри функции пытаются обратиться к NEW как к таблице, а не как к записи. В этой статье мы подробно разберём причину ошибки и покажем правильный синтаксис.
Почему возникает ошибка «отношение new не существует»?
В PostgreSQL ключевое слово NEW - это не таблица, а специальная переменная-запись (record), доступная только в триггерных функциях. Она содержит новую версию строки для операций INSERT и UPDATE. Ошибка появляется, когда вы пытаетесь выполнить SELECT ... FROM NEW, как если бы NEW была обычной таблицей.
Пример неправильного кода
CREATE FUNCTION trigger_test_func() RETURNS TRIGGER AS $$
DECLARE
v TEXT;
BEGIN
SELECT txt INTO v FROM new; -- Ошибка! new воспринимается как таблица
INSERT INTO test_after(val) VALUES(v);
END;
$$ LANGUAGE plpgsql;Здесь FROM new заставляет PostgreSQL искать таблицу с именем new, которая не существует. Вместо этого нужно обращаться к полям напрямую через NEW.txt.
Как правильно использовать NEW в триггерной функции
Для доступа к данным новой строки используйте синтаксис NEW.имя_поля без SELECT. Вот корректная версия функции:
CREATE FUNCTION trigger_test_func() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO test_after(val) VALUES(NEW.txt);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;Обратите внимание на два важных момента:
- Прямое обращение к полю:
NEW.txt- это значение колонкиtxtиз новой строки. - RETURN NEW: триггерная функция должна возвращать запись, соответствующую типу триггера (для INSERT -
NEW).
Полный пример рабочего триггера
Создадим таблицы и корректный триггер для демонстрации:
-- Таблица-источник
CREATE TABLE test (id SERIAL PRIMARY KEY, txt TEXT);
-- Таблица для логирования
CREATE TABLE test_after (id SERIAL PRIMARY KEY, val TEXT);
-- Триггерная функция
CREATE FUNCTION log_insert() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO test_after(val) VALUES(NEW.txt);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Триггер
CREATE TRIGGER trigger_test
AFTER INSERT ON test
FOR EACH ROW
EXECUTE FUNCTION log_insert();
-- Проверка
INSERT INTO test(txt) VALUES('mytext');
-- Теперь в test_after появится запись со значением 'mytext'Распространённые ошибки при работе с NEW и OLD
Помимо описанной проблемы, встречаются и другие типичные ошибки:
Забыли RETURN NEW или RETURN OLD
Триггерная функция должна возвращать соответствующую запись. Для BEFORE INSERT - RETURN NEW, для AFTER DELETE - RETURN OLD. Если не указать RETURN, PostgreSQL выдаст ошибку.
Использование OLD в триггере INSERT
Переменная OLD доступна только для операций UPDATE и DELETE. В триггере INSERT она не определена, и попытка обратиться к OLD.txt вызовет ошибку.
Неправильный тип триггера
Убедитесь, что триггер объявлен с правильным событием (BEFORE или AFTER) и уровнем (FOR EACH ROW или FOR EACH STATEMENT). Для доступа к NEW необходим построчный триггер (FOR EACH ROW).
Заключение
Ошибка «отношение new не существует» возникает из-за неверного синтаксиса: нельзя писать SELECT ... FROM NEW. Используйте прямое обращение NEW.поле и всегда возвращайте NEW или OLD в зависимости от типа операции. Следуя этим правилам, вы легко создадите рабочие триггеры в PostgreSQL.