SQL As Understood By SQLite

CREATE TRIGGER

sql-statement ::= CREATE [TEMP | TEMPORARY] TRIGGER [IF NOT EXISTS] trigger-name [ BEFORE | AFTER ]
database-event ON [database-name .] table-name
trigger-action
sql-statement ::= CREATE [TEMP | TEMPORARY] TRIGGER [IF NOT EXISTS] trigger-name INSTEAD OF
database-event ON [database-name .] view-name
trigger-action
database-event ::= DELETE |
INSERT
|
UPDATE
|
UPDATE OF
column-list
trigger-action ::= [ FOR EACH ROW ] [ WHEN expression ]
BEGIN
    
trigger-step ; [ trigger-step ; ]*
END
trigger-step ::= update-statement | insert-statement |
delete-statement | select-statement

CREATE TRIGGER 语句用于向数据库模式中添加触发器。 触发器是当一个数据库事件(databae-event) 发生时由数据库自动完成的一个操作。

一个触发器可以在一个特定表上执行DELETE、INSERT 或 UPDATE 时触发, 或者任何时候更新一个表的特定一列或几列时触发。

当前,SQLite仅支持 FOR EACH ROW 触发器triggers,而不支持FOR EACH STATEMENT 触发器。所以,明确的指定 FOR EACH ROW 是可选的。FOR EACH ROW暗指 trigger-steps 所指定的的SQL语句会在数据库的每一行被插入、更新或删除时触发 (依赖于WHEN子句)。

WHEN 子句和 trigger-steps 都可以通过引用 “NEW.column-name”和“OLD.column-name”来访问被插入、删除或者新的行元素。 其中,column-name 是触发器相关的表中的列名。 OLD 和 NEW 引用只能用于由 trigger-events 所触发的相关的触发器中,如下:

INSERT NEW 引用是合法的
UPDATE NEW 和 OLD 引用者是合法的
DELETE OLD 引用是合法的

如果提供 WHEN 子句,那么由 trigger-steps 所指定的语句只有在那些使 WHEN 子句为真的行上才会执行。 若没有WHEN子句,在所有行上都会执行。

指定 trigger-time 决定相对于插入、修改或删除相关的行来说, trigger-steps何时被执行。

在一个UPDATE或INSERT的trigger-step中可以包含 ON CONFLICT 子句, 但是,如果一个 ON CONFLICT 子句被指定为引起触发器行动的语句的一部分, 将会以该种冲突处理策略来代替。

当触发器相关的表被删除时,触发器也会自动删除。

通过在 CREATE TRIGGER 时指定 INSTEAD OF,也可以在视图上创建触发器, 就象在表上建一样。如果视图上定义了一个或几个 ON INSERT、 ON DELETE 或 ON UPDATE 触发器,那么当在视图上分别执行一个INSERT、DELETE 或 UPDATE 语句时就不会出错。 其后,在视图上执行INSERT、DELETE 或 UPDATE 将会触发相关的触发器。正常情况下,与视图相关的真实表是不会被修改的 (除非明确使用触发器)。

例子:

假设客户记录存储在 "customers" 表中,其定单记录存储在 "orders" 表中, 下面的触发器将保证在一个客户更改地址时,所有相关的定单都会跟着修改:

CREATE TRIGGER update_customer_address UPDATE OF address ON customers 
  BEGIN
    UPDATE orders SET address = new.address WHERE customer_name = old.name;
  END;

安装上触发器后,执行如下语句:

UPDATE customers SET address = '1 Main St.' WHERE name = 'Jack Jones';

将会导致下列语句自动执行:

UPDATE orders SET address = '1 Main St.' WHERE customer_name = 'Jack Jones';

需要注意的是,当前,定义在有INTEGER PRIMARY KEY字段的表上的触发器可能会产生怪异的行为。 如果一个定义在 INTEGER PRIMARY KEY 字段上的 BEFORE 触发器修改一行的 INTEGER PRIMARY KEY 字段,而该字段又将被引发触发器的语句所更新, 那么更新操作将不会发生。绕过这一问题的办法是声明一列为 PRIMARY KEY 而非 INTEGER PRIMARY KEY。

在一个触发器程序中,可以使用一个特殊的SQL函数 RAISE() ,语法如下:

raise-function ::= RAISE ( ABORT, error-message ) |
RAISE ( FAIL,
error-message ) |
RAISE ( ROLLBACK,
error-message ) |
RAISE ( IGNORE )

当在触发器程序执行期间,按前面三种方式调用时,当前的查询会终止, 指定的 ON CONFLICT 过程将会执行(或者是 ABORT, FAIL 或 ROLLBACK)。 用户会得到一个 SQLITE_CONSTRAINT 错误代码,并伴有指定的出错信息。

当调用 RAISE(IGNORE) 时,当前触发器中后面的程序,引发触发器动作的语句, 以及任何后续本应该执行的触发器程序都会被丢弃。 数据库回滚且无任何改变。如果引发触发器程序的语句本身是触发器程序的一部分, 那么,该触发器程序将在下一步的开始继续执行。

触发器可以使用 DROP TRIGGER 删除。