CREATE TRIGGER#

CREATE TRIGGER

CREATE TRIGGER

CREATE TRIGGER — определить новый триггер

Синтаксис

CREATE [ OR REPLACE ] [ CONSTRAINT ] TRIGGER name { BEFORE | AFTER | INSTEAD OF } { event [ OR ... ] }
    ON table_name
    [ FROM referenced_table_name ]
    [ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ]
    [ REFERENCING { { OLD | NEW } TABLE [ AS ] transition_relation_name } [ ... ] ]
    [ FOR [ EACH ] { ROW | STATEMENT } ]
    [ WHEN ( condition ) ]
    EXECUTE { FUNCTION | PROCEDURE } function_name ( arguments )

where event can be one of:

    INSERT
    UPDATE [ OF column_name [, ... ] ]
    DELETE
    TRUNCATE

Описание

Создание триггера с помощью команды CREATE TRIGGER создает новый триггер. Команда CREATE OR REPLACE TRIGGER создает новый триггер или заменяет существующий. Триггер будет связан с указанной таблицей, представлением или внешней таблицей и будет выполнять указанную функцию function_name при выполнении определенных операций с этой таблицей.

Чтобы заменить текущее определение существующего триггера, используйте CREATE OR REPLACE TRIGGER, указав имя существующего триггера и родительскую таблицу. Все остальные свойства заменяются.

Триггер может быть указан для срабатывания перед попыткой выполнения операции над строкой (перед проверкой ограничений и попыткой выполнения команды INSERT, UPDATE или DELETE); или после завершения операции (после проверки ограничений и завершения команды INSERT, UPDATE или DELETE); или вместо операции (в случае вставки, обновления или удаления в представлении). Если триггер срабатывает перед или вместо события, триггер может пропустить операцию для текущей строки или изменить вставляемую строку (только для операций INSERT и UPDATE). Если триггер срабатывает после события, все изменения, включая эффекты других триггеров, являются "видимыми" для триггера.

Каждый триггер, помеченный тегом FOR EACH ROW, вызывается один раз для каждой строки, которую операция изменяет. Например, DELETE, который затрагивает 10 строк, вызовет выполнение триггеров ON DELETE на целевом отношении 10 раз, по одному разу для каждой удаленной строки. В отличие от этого, триггер, помеченный тегом FOR EACH STATEMENT, выполняется только один раз для любой данной операции, независимо от количества изменяемых строк (в частности, операция, которая не изменяет ни одной строки, все равно приведет к выполнению всех применимых триггеров FOR EACH STATEMENT).

Все триггеры, которые указаны для срабатывания INSTEAD OF события триггера, должны быть помечены FOR EACH ROW и могут быть определены только для представлений. Триггеры BEFORE и AFTER на представлении должны быть помечены как FOR EACH STATEMENT.

В дополнение к этому, триггеры могут быть определены для срабатывания при TRUNCATE, хотя только FOR EACH STATEMENT.

Следующая таблица содержит сводку о том, какие типы триггеров могут быть использованы на таблицах, представлениях и внешних таблицах:

КогдаСобытиеУровень строкиУровень оператора
BEFOREINSERT/UPDATE/DELETEТаблицы и внешние таблицыТаблицы, представления и внешние таблицы
TRUNCATEТаблицы
AFTERINSERT/UPDATE/DELETEТаблицы и внешние таблицыТаблицы, представления и внешние таблицы
TRUNCATEТаблицы
INSTEAD OFINSERT/UPDATE/DELETEПредставления
TRUNCATE

Также, определение триггера может указывать логическое условие WHEN, которое будет проверяться для определения, должен ли триггер срабатывать. В триггерах на уровне строк условие WHEN может проверять старые и/или новые значения столбцов строки. Триггеры на уровне операторов также могут иметь условия WHEN, хотя эта возможность не так полезна для них, так как условие не может ссылаться на значения в таблице.

Если для одного и того же события определено несколько триггеров одного типа, они будут запускаться в алфавитном порядке по имени.

Когда указывается опция CONSTRAINT, эта команда создает триггер ограничения. Это то же самое, что и обычный триггер, за исключением того, что время срабатывания триггера может быть настроено с помощью SET CONSTRAINTS. Триггеры ограничений должны быть триггерами AFTER ROW на обычных таблицах (не на внешних таблицах). Они могут срабатывать либо в конце оператора, вызывающего событие, либо в конце содержащей транзакции; в последнем случае они называются отложенными. Отложенное срабатывание отложенного триггера также может быть принудительно вызвано немедленно с помощью SET CONSTRAINTS. Ожидается, что триггеры ограничений вызовут исключение, когда нарушаются реализуемые ими ограничения.

Опция REFERENCING позволяет собирать переходные отношения, которые представляют собой наборы строк, включающие все строки, вставленные, удаленные или измененные текущим оператором SQL. Эта функция позволяет триггеру видеть глобальное представление о том, что делал оператор, а не только одну строку за раз. Эта опция разрешена только для триггера AFTER, который не является триггером ограничения; кроме того, если триггер является триггером UPDATE, он не должен указывать список column_name. OLD TABLE может быть указан только один раз и только для триггера, который может срабатывать на UPDATE или DELETE; он создает переходное отношение, содержащее предварительные изображения всех строк, обновленных или удаленных оператором. Аналогично, NEW TABLE может быть указан только один раз и только для триггера, который может срабатывать на UPDATE или INSERT; он создает переходное отношение, содержащее последующие изображения всех строк, обновленных или вставленных оператором.

SELECT не изменяет ни одну строку, поэтому вы не можете создавать триггеры SELECT. Правила и представления могут предоставить рабочие решения для проблем, которые, кажется, требуют триггеров SELECT.

Ссылка на Глава 37 содержит дополнительную информацию о триггерах.

Параметры

name

Имя, которое следует присвоить новому триггеру. Оно должно отличаться от имени любого другого триггера для той же таблицы. Имя не может содержать указание схемы - триггер наследует схему своей таблицы. Для триггера-ограничения это также имя, которое следует использовать при изменении поведения триггера с помощью команды SET CONSTRAINTS.

BEFORE
AFTER
INSTEAD OF

Определяет, вызывается ли функция перед, после или вместо события. Ограничительный триггер может быть указан только как AFTER.

event

Один из INSERT, UPDATE, DELETE или TRUNCATE; это указывает событие, которое вызовет триггер. Можно указать несколько событий, используя OR, за исключением случаев, когда запрашиваются переходные отношения.

Для событий UPDATE возможно указать список столбцов с использованием следующего синтаксиса:

UPDATE OF column_name1 [, column_name2 ... ]

Триггер будет срабатывать только в том случае, если хотя бы одна из указанных колонок упоминается как цель команды UPDATE или если одна из указанных колонок является вычисляемой колонкой, зависящей от колонки, которая является целью команды UPDATE.

Вместо обновления события INSTEAD OF UPDATE не позволяют указывать список столбцов. При запросе переходных отношений также нельзя указывать список столбцов.

table_name

Имя (опционально с указанием схемы) таблицы, представления или внешней таблицы, для которой предназначен триггер.

referenced_table_name

Имя (возможно, с указанием схемы) другой таблицы, на которую ссылается ограничение. Этот параметр используется для ограничений внешнего ключа и не рекомендуется для общего использования. Это можно указать только для триггеров ограничений.

DEFERRABLE
NOT DEFERRABLE
INITIALLY IMMEDIATE
INITIALLY DEFERRED

Время выполнения триггера по умолчанию. См. документацию по CREATE TABLE для получения подробной информации о этих параметрах ограничений. Это можно указать только для триггеров-ограничений.

REFERENCING

Это ключевое слово непосредственно предшествует объявлению одного или двух имен отношений, которые обеспечивают доступ к переходным отношениям вызывающего оператора.

OLD TABLE
NEW TABLE

Это предложение указывает, является ли следующее имя отношения для отношения перехода до изображения или отношения перехода после изображения.

transition_relation_name

Неполное имя, которое будет использоваться внутри триггера для этого переходного отношения.

FOR EACH ROW
FOR EACH STATEMENT

Это указывает, должна ли функция триггера быть запущена один раз для каждой строки, затронутой событием триггера, или только один раз для каждого SQL-запроса. Если ни одно из них не указано, по умолчанию используется FOR EACH STATEMENT. Ограничительные триггеры можно указать только FOR EACH ROW.

condition

Логическое выражение, определяющее, будет ли фактически выполнена функция триггера. Если указано WHEN, функция будет вызвана только в том случае, если условие возвращает true. В триггерах FOR EACH ROW условие WHEN может ссылаться на столбцы старых и/или новых значений строки, записывая соответственно OLD.имя_столбца или NEW.имя_столбца. Конечно, триггеры INSERT не могут ссылаться на OLD, а триггеры DELETE не могут ссылаться на NEW.

INSTEAD OF триггеры не поддерживают условия WHEN.

В настоящее время выражения WHEN не могут содержать подзапросы.

Обратите внимание, что для триггеров ограничений, оценка условия WHEN не откладывается, а выполняется непосредственно после выполнения операции обновления строки. Если условие не оценивается как истинное, триггер не ставится в очередь для отложенного выполнения.

function_name

Пользовательская функция, которая объявляется без аргументов и возвращает тип trigger, и которая выполняется при срабатывании триггера.

В синтаксисе CREATE TRIGGER ключевые слова FUNCTION и PROCEDURE эквивалентны, но ссылочная функция должна быть всегда функцией, а не процедурой. Использование ключевого слова PROCEDURE здесь является историческим и устаревшим.

arguments

Необязательный список аргументов, разделенных запятыми, которые будут переданы функции при выполнении триггера. Аргументы являются литеральными строковыми константами. Здесь также можно указывать простые имена и числовые константы, но они все будут преобразованы в строки. Пожалуйста, ознакомьтесь с описанием языка реализации триггерной функции, чтобы узнать, как эти аргументы могут быть доступны внутри функции; это может отличаться от обычных аргументов функции.

Примечания

Для создания или замены триггера на таблице пользователь должен иметь привилегию TRIGGER на эту таблицу. Пользователь также должен иметь привилегию EXECUTE на функцию триггера.

Используйте DROP TRIGGER для удаления триггера.

Создание триггера на уровне строки на разделенной таблице приведет к созданию идентичного триггера-клона на каждом из ее существующих секций; и любые созданные или присоединенные позднее секции также будут иметь идентичный триггер. Если на дочерней секции уже существует триггер с конфликтующим именем, происходит ошибка, если не используется команда CREATE OR REPLACE TRIGGER, в этом случае этот триггер заменяется триггером-клоном. При отсоединении секции от родительской секции его триггеры-клоны удаляются.

Триггер, специфичный для столбца (определенный с использованием синтаксиса UPDATE OF column_name), сработает, когда любой из его столбцов указан в качестве цели в списке UPDATE команды SET. Возможно изменение значения столбца, даже если триггер не сработал, потому что изменения, внесенные в содержимое строки триггерами BEFORE UPDATE, не учитываются. С другой стороны, команда вроде UPDATE ... SET x = x ... сработает триггер на столбце x, даже если значение столбца не изменилось.

В триггере BEFORE условие WHEN вычисляется непосредственно перед выполнением функции или перед тем, как она будет выполнена, поэтому использование WHEN практически не отличается от проверки того же условия в начале функции триггера. Обратите внимание, что строка NEW, видимая условием, является текущим значением, возможно, измененным предыдущими триггерами. Кроме того, условие WHEN триггера BEFORE не может проверять системные столбцы строки NEW (например, ctid), потому что они еще не будут установлены.

В триггере AFTER условие WHEN вычисляется сразу после обновления строки и определяет, будет ли событие поставлено в очередь для запуска триггера в конце оператора. Таким образом, если условие WHEN триггера AFTER не возвращает истинное значение, нет необходимости ставить событие в очередь или повторно получать строку в конце оператора. Это может привести к значительному ускорению выполнения операторов, которые изменяют много строк, если триггер должен быть запущен только для нескольких строк.

В некоторых случаях одна SQL-команда может вызывать несколько типов триггеров. Например, команда INSERT с фразой ON CONFLICT DO UPDATE может вызывать как операции вставки, так и обновления, поэтому она будет вызывать соответствующие триггеры при необходимости. Переходные отношения, передаваемые триггерам, специфичны для их типа события; таким образом, триггер INSERT будет видеть только вставленные строки, в то время как триггер UPDATE будет видеть только обновленные строки.

Все обновления или удаления строк, вызванные действиями обеспечения ссылочной целостности, такими как ON UPDATE CASCADE или ON DELETE SET NULL, рассматриваются как часть SQL-команды, вызвавшей их (обратите внимание, что такие действия никогда не откладываются). Соответствующие триггеры на затронутой таблице будут запущены, что предоставляет еще один способ, с помощью которого SQL-команда может запускать триггеры, не соответствующие непосредственно ее типу. В простых случаях триггеры, запрашивающие переходные отношения, будут видеть все изменения, вызванные в их таблице одной исходной SQL-командой, как одно переходное отношение. Однако есть случаи, когда наличие триггера AFTER ROW, запрашивающего переходные отношения, приводит к тому, что действия обеспечения ссылочной целостности, вызванные одной SQL-командой, разделяются на несколько шагов, каждый со своими переходными отношениями. В таких случаях любые триггеры на уровне оператора, которые присутствуют, будут запущены один раз для каждого создания набора переходных отношений, гарантируя, что триггеры видят каждую затронутую строку в переходном отношении один раз и только один раз.

Все триггеры на уровне оператора для представления срабатывают только в том случае, если действие над представлением обрабатывается триггером на уровне строки INSTEAD OF. Если действие обрабатывается правилом INSTEAD, то все операторы, генерируемые правилом, выполняются вместо исходного оператора, указывающего на представление, так что срабатывают триггеры на таблицах, указанных в заменяющих операторах. Аналогично, если представление автоматически обновляемо, то действие обрабатывается автоматическим переписыванием оператора в действие над базовой таблицей представления, так что срабатывают триггеры на уровне оператора базовой таблицы.

Изменение разделенной таблицы или таблицы с дочерними таблицами наследования вызывает триггеры уровня оператора, присоединенные к явно указанной таблице, но не триггеры уровня оператора для ее секций или дочерних таблиц. В отличие от этого, триггеры уровня строки срабатывают на строках в затронутых разделах или дочерних таблицах, даже если они не явно указаны в запросе. Если триггер уровня оператора был определен с переходными отношениями, указанными в предложении REFERENCING, то до и после изображения строк видны из всех затронутых секций или дочерних таблиц. В случае дочерних таблиц наследования, изображения строк включают только столбцы, присутствующие в таблице, к которой присоединен триггер.

В настоящее время невозможно определить триггеры на уровне строк с переходными отношениями на секции или дочерние таблицы наследования. Кроме того, триггеры на разделенных таблицах не могут быть INSTEAD OF.

В настоящее время опция OR REPLACE не поддерживается для триггеров ограничений.

Замена существующего триггера внутри транзакции, которая уже выполнила действия по обновлению таблицы триггера, не рекомендуется. Решения о срабатывании триггера или его частей, которые уже были приняты, не будут пересматриваться, поэтому результаты могут быть неожиданными.

Существует несколько встроенных функций триггеров, которые могут быть использованы для решения общих проблем без необходимости написания собственного кода триггеров; см. Раздел 9.28.

Примеры

Выполните функцию check_account_update каждый раз, когда строка таблицы accounts собирается быть обновлена:

CREATE TRIGGER check_update
    BEFORE UPDATE ON accounts
    FOR EACH ROW
    EXECUTE FUNCTION check_account_update();

Измените определение триггера так, чтобы функция выполнялась только в том случае, если столбец balance указан в качестве цели в команде UPDATE:

CREATE OR REPLACE TRIGGER check_update
    BEFORE UPDATE OF balance ON accounts
    FOR EACH ROW
    EXECUTE FUNCTION check_account_update();

Эта форма выполняет функцию только в том случае, если значение столбца balance действительно изменилось:

CREATE TRIGGER check_update
    BEFORE UPDATE ON accounts
    FOR EACH ROW
    WHEN (OLD.balance IS DISTINCT FROM NEW.balance)
    EXECUTE FUNCTION check_account_update();

Вызовите функцию для регистрации обновлений accounts, но только если что-то изменилось:

CREATE TRIGGER log_update
    AFTER UPDATE ON accounts
    FOR EACH ROW
    WHEN (OLD.* IS DISTINCT FROM NEW.*)
    EXECUTE FUNCTION log_account_update();

Выполните функцию view_insert_row для каждой строки, чтобы вставить строки в таблицы, лежащие в основе представления:

CREATE TRIGGER view_insert
    INSTEAD OF INSERT ON my_view
    FOR EACH ROW
    EXECUTE FUNCTION view_insert_row();

Выполните функцию check_transfer_balances_to_zero для каждого оператора, чтобы подтвердить, что строки transfer суммируются в ноль:

CREATE TRIGGER transfer_insert
    AFTER INSERT ON transfer
    REFERENCING NEW TABLE AS inserted
    FOR EACH STATEMENT
    EXECUTE FUNCTION check_transfer_balances_to_zero();

Выполните функцию check_matching_pairs для каждой строки, чтобы подтвердить, что изменения в парах происходят одновременно (одним и тем же оператором):

CREATE TRIGGER paired_items_update
    AFTER UPDATE ON paired_items
    REFERENCING NEW TABLE AS newtab OLD TABLE AS oldtab
    FOR EACH ROW
    EXECUTE FUNCTION check_matching_pairs();

Раздел 37.4 содержит полный пример функции триггера, написанной на языке C.

Совместимость

Оператор CREATE TRIGGER в Tantor SE реализует подмножество стандарта SQL. В настоящее время отсутствуют следующая функциональность:

  • В то время как имена таблиц перехода для триггеров AFTER указываются с использованием стандартного синтаксиса в разделе REFERENCING, переменные строк, используемые в триггерах FOR EACH ROW, нельзя указать в разделе REFERENCING. Они доступны в зависимости от языка, на котором написана функция триггера, но они фиксированы для каждого языка. Некоторые языки эффективно ведут себя так, как если бы был раздел REFERENCING, содержащий OLD ROW AS OLD NEW ROW AS NEW.

  • Стандарт позволяет использовать таблицы переходов с специфичными для столбца триггерами UPDATE, но тогда набор строк, которые должны быть видимы в таблицах переходов, зависит от списка столбцов триггера. В настоящее время это не реализовано в Tantor SE.

  • Tantor SE позволяет выполнение только пользовательской функции для вызванного действия. Стандарт позволяет выполнение ряда других SQL-команд, таких как CREATE TABLE, в качестве вызванного действия. Это ограничение легко обойти, создав пользовательскую функцию, которая выполняет нужные команды.

SQL указывает, что несколько триггеров должны быть запущены в порядке их создания. Tantor SE использует порядок по имени, который был признан более удобным.

SQL указывает, что триггеры BEFORE DELETE на каскадных удалениях срабатывают после завершения каскадного DELETE. Поведение Tantor SE состоит в том, что триггер BEFORE DELETE всегда срабатывает перед действием удаления, даже каскадным. Это считается более последовательным. Также существует нестандартное поведение, если триггеры BEFORE изменяют строки или предотвращают обновления во время обновления, вызванного референциальным действием. Это может привести к нарушениям ограничений или хранению данных, не соответствующих референциальному ограничению.

Возможность указать несколько действий для одного триггера, используя тег OR, является расширением Tantor SE стандарта SQL.

Возможность запуска триггеров для команды TRUNCATE является расширением Tantor SE стандарта SQL, также как и возможность определения триггеров на уровне операторов для представлений.

CREATE CONSTRAINT TRIGGER - это расширение Tantor SE стандарта SQL. Также является расширением опция OR REPLACE.