Ошибка «отношение 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.

    Часто задаваемые вопросы