CREATE TRIGGER#
CREATE TRIGGER
CREATE TRIGGER — определить новый триггер
Синтаксис
CREATE [ OR REPLACE ] [ CONSTRAINT ] TRIGGERname
{ BEFORE | AFTER | INSTEAD OF } {event
[ OR ... ] } ONtable_name
[ FROMreferenced_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
) whereevent
can be one of: INSERT UPDATE [ OFcolumn_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
.
Следующая таблица содержит сводку о том, какие типы триггеров могут быть использованы на таблицах, представлениях и внешних таблицах:
Когда | Событие | Уровень строки | Уровень оператора |
---|---|---|---|
BEFORE | INSERT /UPDATE /DELETE | Tables and foreign tables | Tables, views, and foreign tables |
TRUNCATE | — | Tables and foreign tables | |
AFTER | INSERT /UPDATE /DELETE | Tables and foreign tables | Tables, views, and foreign tables |
TRUNCATE | — | Tables and foreign tables | |
INSTEAD OF | INSERT /UPDATE /DELETE | Views | — |
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
.
Ссылка на Глава 36 содержит дополнительную информацию о триггерах.
Параметры
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();
Раздел 36.4 содержит полный пример триггерной функции, написанной на языке C.
Совместимость
Оператор CREATE TRIGGER
в Tantor SE-1C реализует подмножество стандарта SQL. В настоящее время отсутствуют следующая функциональность:
В то время как имена таблиц перехода для триггеров
AFTER
указываются с использованием стандартного синтаксиса в разделеREFERENCING
, переменные строк, используемые в триггерахFOR EACH ROW
, нельзя указать в разделеREFERENCING
. Они доступны в зависимости от языка, на котором написана триггерная функция, но они фиксированы для каждого языка. Некоторые языки эффективно ведут себя так, как если бы был разделREFERENCING
, содержащийOLD ROW AS OLD NEW ROW AS NEW
.Стандарт позволяет использовать таблицы переходов с специфичными для столбца триггерами
UPDATE
, но тогда набор строк, которые должны быть видимы в таблицах переходов, зависит от списка столбцов триггера. В настоящее время это не реализовано в Tantor SE-1C.Tantor SE-1C позволяет выполнение только пользовательской функции для вызванного действия. Стандарт позволяет выполнение ряда других SQL-команд, таких как
CREATE TABLE
, в качестве вызванного действия. Это ограничение легко обойти, создав пользовательскую функцию, которая выполняет нужные команды.
SQL указывает, что несколько триггеров должны быть запущены в порядке их создания. Tantor SE-1C использует порядок по имени, который был признан более удобным.
SQL указывает, что триггеры BEFORE DELETE
на каскадных
удалениях срабатывают после завершения каскадного
DELETE
.
Поведение Tantor SE-1C состоит в том, что триггер BEFORE
DELETE
всегда срабатывает перед действием удаления, даже каскадным.
Это считается более последовательным. Также существует нестандартное
поведение, если триггеры BEFORE
изменяют строки или предотвращают
обновления во время обновления, вызванного референциальным действием.
Это может привести к нарушениям ограничений или хранению данных, не соответствующих
референциальному ограничению.
Возможность указать несколько действий для одного триггера, используя OR
, является расширением Tantor SE-1C стандарта SQL.
Возможность запуска триггеров для команды TRUNCATE
является расширением Tantor SE-1C стандарта SQL, также как и возможность определения триггеров на уровне операторов для представлений.
CREATE CONSTRAINT TRIGGER
- это расширение Tantor SE-1C стандарта SQL.
Также является расширением опция OR REPLACE
.