返回首页

gbase数据、南大通用产品文档:GBase8s

更新日期:2024年09月11日

CREATE TRIGGER 语句
使用 CREATE TRIGGER 语句在表上定义触发器。您还可以使用 CREATE
TRIGGER 在视图上定义 INSTEAD OF 触发器。
该语句是 SQL ANSI/ISO 标准的扩展。
语法


元素
描述
限制
语法
trigger 此处为新的触发器
声明的名称
必须在当前数据库中的触发
器名称中是唯一的
标识符
用法
除非被禁用。否则当指定的触发事件事件发生时,触发器将自动执行指定的 SQL
语句集合,称为触发器操作。
启动触发器操作的触发事件可以是 INSERT 、DELETE 、UPDATE 或 SELECT
语句。MERGE 语句还可以是 UPDATE 、DELETE 或 INSERT 触发的触发事

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 446
件。该事件必须指定定义触发器的表或视图。(表上的触发器的 SELECT 或
UPDATE 事件还可以指定一列或多列。)
您可以用两种不同方法使用 CREATE TRIGGER 语句:

可以在当前数据库中的表上定义触发器。

也可以在当前数据库中的视图上定义 INSTEAD OF 触发器。
作为触发事件的实例的任何 SQL 语句称为触发语句。当事件发生时,在表上定
义的触发器和在视图上定义的事件在是否执行触发语句方面有所不同:

对于表,触发事件和触发器操作都执行。

对于视图,只有触发器操作执行,而触发事件不执行。
通过定义指定的 DML 操作(触发事件)使数据库服务器执行特定操作所依据的
规则,CREATE TRIGGER 语句可以支持数据库中数据的完整性。以下各节描述
了语法元素。
子句

作用
OR REPLACE 子

OR REPLACE
创建或替换触发器
定义触发器事
件和操作
定义触发器事件和操作
将触发器的操作与事件关

触发器模式
触发器方式
启用或禁用此触发器
Insert 事件和
Delete 事件
INSERT 事件和 DELETE 事件
定义 Insert 事件和
Delete 事件
Update 事件
UPDATE 事件
定义 Update 事件
Select 事件
SELECT 事件
定义 Select 事件
Action 子句
Action 子句
定义触发器操作
用于 Delete

REFERENCING
子句
用于删除的 REFERENCING 子句
为已删除的值声明限定符

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 447
子句

作用
用于 Insert

REFERENCING
子句
用于插入的 REFERENCING 子句
为已插入的值声明限定符
用于 Update
的REFERENCING
子句
用于更新的 REFERENCING 子句
为新的和旧的值定义限定

用于 Select
的REFERENCING
子句
用于选择的 REFERENCING 子句
为结果集值声明限定符
相关的表操作
相关的表操作
定义触发器的操作
触发器操作
触发操作
定义触发器的操作
视图上的
INSTEAD OF 触
发器
视图上的 INSTEAD OF 触发器
定义视图上的触发器
INSTEAD OF 触
发器的 Action
子句
INSTEAD OF 触发器的 Action 子

视图上的触发操作
OR REPLACE
指定 OR REPLACE (CREATE OR REPLACE TRIGGER) 将创建一个新触发器或
替换同名的现有触发器。
要添加触发器,您必须是该触发器的 Owner 或持有对该数据库的 DBA 权限。
以下示例语句创建触发器 tr1:
create or replace trigger tr1 ……;
在该语句完成后,若继续执行此语句,将替换上一个示例中创建的 tr1 触发器。
此时,要替换已创建的 tr1 触发器,您必须是此触发器的所有者或持有 DBA 权
限的才能成功执行此语句。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 448
定义触发器事件和操作
此语法定义表上或视图上的触发器的事件和操作。
表上的触发器

DELETE 和 SELECT 子子句

UPDATE 子子句

视图上触发器

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 449

元素
描述
限制
语法
column
触发表中的列名称
必须存在
标识符
correlation
您此处声明的在触发操作中限定的
旧的或新的列值
( correlation.column)
在此触发器
中必须是唯
一的
标识符
table, view
触发表或视图的名称或同义词。
table 或 view 可以包含 owner.
限定符。
必须存在于
当前数据库

标识符
主图表(包含表或视图)的左侧部分定义触发器事件(有时称为触发事件)。图
表的剩余部分声明相关名称并定义触发器操作(有时称为触发器操作)。(对于
表上的触发器,请参阅 Action 子句 和 相关的表操作 。有关视图上的
INSTEAD OF 触发器,请参阅 INSTEAD OF 触发器的 Action 子句。)
触发器上的限制
要在表上创建触发器(或在视图上创建 INSTEAD OF 触发器),您必须拥有表
或视图,或具有 DBA 状态。关于触发器所有者特权和其它用户特权之间的关
系,请参阅执行触发操作的特权。
您创建触发器的表必须存在于当前数据库中。您不能在任一以下类型的表上创建
触发器:

诊断表、违例表或另一个数据库中的表

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 450

临时表或系统目录表

CREATE EXTERNAL TABLE 或 CREATE SEQUENCE 语句创建的表对
象。
在 DB-Access 中,如果您想将触发器定义为模式的一部分,则请将 CREATE
TRIGGER 语句放在 CREATE SCHEMA 语句中。
如果您正将 CREATE TRIGGER 语句嵌入到 GBase 8s ESQL/C 程序中,则您不
能在触发器定义中使用主变量。
可以使用 DROP TRIGGER 语句移除现有的触发器。如果使用 DROP TABLE 或
DROP VIEW 语句来从数据库除去触发表或视图,则那些表或视图上的所有触发
器也被删除。
当从触发器示例中或从触发器的 Action 子句或 Correlated Action 子句发出 SPL
的 ON EXCEPTION 语句时,该语句不会生效。
触发 BIGSERIAL 、 SERIAL 或 SERIAL8 列递增的 Insert 触发器的触发操作
不会更改 SQL 通信区域结构的 sqlca.sqlerrd[1] 字段。该触发 INSERT 操作可
以成功增加该列的序列计数,但是 sqlca.sqlerrd[1] 字段的值仍为零,而不会重置
为新的序列值。
不能在指定了ON DELETE CASCADE 引用约束的表上定义 DELETE 触发器。
UNION 子查询不能是触发事件。如果一个有效的 UNION 子查询指定了 Select
触发器定义的列,该查询成功,但是会忽略此触发器(或者视图上的 INSTEAD
OF 触发器)。
数据库服务器不会对一些触发器使用并行处理。对于与触发事件类型相对应的任
何 DML 语句,PDQ 在 FOR EACH ROW 部分中自动禁用:

在 Select 触发器的 Action 子句中的 SELECT 语句

在 Delete 触发器的 Action 子句中的 DELETE 或 MERGE 语句

在 Insert 触发器的 Action 子句中的 INSERT 或 MERGE 语句

在 Update 触发器的 Action 子句中的 UPDATE 或 MERGE 语句。
对 PDQ 的此限制的作用域是 FOR EACH ROW 部分。它在 Action 子句的
BEFORE 或 AFTER 部分中的 DML 语句没有作用。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 451
有关视图上 INSTEAD OF 触发器其它限制,请参阅视图上 INSTEAD OF 触发器
的限制 。
触发器方式
您可以在创建触发器时将触发器方式设置为启用或禁用触发器。
触发器方式

您可以以 ENABLED 或 DISABLED 方式在表或视图上创建触发器。

当以 ENABLED 方式创建触发器时,如果发生触发事件,则数据库服务
器执行触发操作。(如果在创建触发器时不指定任何方式,则
ENABLED 是缺省方式。)

当以 DISABLED 方式创建触发器时,触发事件不会导致执行触发操作。
实际上,数据库服务器将忽略该触发器及其操作。即使 systriggers 系统
目录表维护有关已禁用触发器的信息。
您也可以使用 Database Object Mode 语句的 SET TRIGGERS 选项将现有的触发
器设置为 ENABLED 或 DISABLED 方式。
通过 SET TRIGGERS 语句启用 DISABLED 触发器后,当发生触发事件时,数据库
服务器可以执行触发操作,但是触发器不逆向执行。对于禁用触发器后和启用触
发器前这段时间内选择、插入、删除或更新的行,数据库服务器将不试图为其执
行触发。
警告: 由于触发器的行为根据其 ENABLED 或 DISABLED 方式而不同,因此禁用
触发器时请小心。如果禁用触发器将最终破坏数据库的语义完整性,则请不要禁
用触发器。
表层级结构中的触发器继承
缺省情况下,任何您定义在 GBase 8s 的类型表上的触发器都会被它的子表继
承。
在此版本的 GBase 8s 中,一个表可以继承多个由同一的触发事件启用的触发
器,因此这些触发器都是为子表上的相同类型的事件所定义的。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 452
在所有版本的 GBase 8s 中,您在子表上设置的触发器会被它的依赖表继承,但
是不会对它的超级表起作用。
当您需要在超级表上启用触发器,但不在其的子表上禁用时,该行为十分重要。
在此版本中,禁用在表层次结构中的表上的触发器不会影响继承触发器。例如,
以下语句对在表层次结构中低于或高于 subtable 的表对象上的触发器没有影
响:
SET TRIGGERS FOR subtable DISABLED
类似地,DROP TRIGGER 语句不能除去继承的触发器,而不移除超级表上的触发
器。在这种情况下,您必须改为在子表上定义一个没有 Action 子句的触发器。因
为触发器未启用,此空的触发器会覆盖继承的触发器并对子表和子表下的任何子
表执行,这些子表不需要进一步覆盖。
触发器和 SPL 例程
您不能如在数据操纵语言语句中列出的那样,在 DML(数据操纵语言)语句中调
用的 SPL 例程中定义触发器。因此,如果 sp_items 过程包含CREATE
TRIGGER 语句,则以下语句返回错误:
INSERT INTO items EXECUTE PROCEDURE sp_items;
您不能将 SQL 的 CREATE FUNCTION 或 CREATE PROCEDURE 语句与
REFERENCING 子句一起使用来定义包含 FOR table 或 FOR view 规范的触发器
例程。这些 UDR 必须包含在指定的表或视图中为 OLD 或 NEW 列值声明的
correlation 名称的 REFERENCING 子句。表或视图上的触发器可以调用来自
Triggered Action 列表中 FOR EACH ROW 部分的触发器例程。触发器还可以调
用来自 Triggered Action 列表 BEFORE 和 AFTER 部分的非触发器例程,但是
这些 UDR 不能使用 correlation 名称来引用 NEW 或 OLD 列值。正如
REFERENCING 子句 中描述的那样,触发器例程中的 REFERENCING 子句支
持与 CREATE TRIGGER 语句相同的语法。
由同一触发事件执行的多个触发器可调用多个触发例程,并且这些例程可以通过
使用具有相同或不同名称的 SPL 变量访问同一 NEW 或 OLD 列值。当一个触
发事件执行多个触发器时,不会授权执行的顺序时,但是所有的 BEFORE 触发
器操作都会在 FOR EACH ROW 触发操作之前执行,而所有的 AFTER 触发操作
会在所有的 FOR EACH ROW 触发操作后执行。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 453
对于不是触发器例程的 UDR ,SPL 变量在 CREATE TRIGGER 语句中无效。
触发器调用的 SPL 例程只能在当前数据库的本地表或本地视图上执行
INSERT 、DELETE 或 UPDATE 操作。另请参阅 SPL 例程的规则以获取关于
触发操作中调用的 SPL 例程的附加限制的信息。
触发事件
触发器事件指定哪个 DML 语句可以启动触发器。事件可以是表或视图上的
INSERT 、DELETE 或 UPDATE 操作,或是查询表的 SELECT 操作。每个
CREATE TRIGGER 语句必须指定一个触发器事件。作为触发事件的实例的任何
SQL 语句都称为触发语句。
对于每个表,您只能定义一个由 INSERT 、DELETE 、UPDATE 或 SELECT
语句的激活的触发器。对于每个视图,您可以定义定义由 INSERT 、DELETE
或 UPDATE 语句激活的 INSTEAD OF 触发器。同一表或视图上的多个触发器可
以被不同类型的触发器事件或同一类型的触发器事件激活。
如果触发表具有指定 ON DELETE CASCADE 的引用约束,则您不能指定
DELETE 事件。
您负责确保触发语句在表上有或没有触发器操作时都返回相同的结果。另请参阅
Action 子句 触发操作部分。
来自外部数据库服务器的触发语句可以激活触发器。
如以下示例所示,newtab 上的 Insert 触发器(由 dbserver1 管理)由来自
dbserver2 的 INSERT 语句激活。该触发器就像在 dbserver1 上生成的 INSERT
那样执行。
-- Trigger on stores_demo@dbserver1:newtab
CREATE TRIGGER ins_tr INSERT ON newtab
REFERENCING new AS post_ins
FOR EACH ROW(EXECUTE PROCEDURE nt_pct (post_ins.mc));
-- Triggering statement from dbserver2
INSERT INTO stores_demo@dbserver1:newtab
SELECT item_num, order_num, quantity, stock_num, manu_code,
total_price FROM items;

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 454
GBase 8s 也支持视图上的 INSTEAD OF 触发器。这些触发器在一个触发 DML
操作引用该指定视图时被启动。INSTEAD OF 触发器使用视图上指定的触发器操
作替换该触发器操作事件,而不是执行触发 INSERT 、DELETE 或 UPDATE 操
作。对于每种事件类型(INSERT 、DELETE 或 UPDATE),视图可以至多定义
多个 INSTEAD OF 触发器。
带游标的触发事件
对于表上的触发器,如果触发器语句使用游标,则触发操作的每个部分(包括
BEFORE 、FOR EACH ROW 和 AFTER ,如果为该触发器指定了的话)都为游
标除了的每行激活。
此行为与触发器语句不使用游标且更新多个行时的情况有所不同。在此情况中,
任何由 BEFORE 和 AFTER 触发的操作都只执行一次,但是 FOR EACH ROW
操作列表对于触发语句处理的每一行都执行。关于触发操作的其它信息,请参阅
Action 子句。
触发事件上的特权
要将触发 INSERT 、DELETE 、UPDATE 或 SELECT 语句执行为触发事件,
您必须在触发表或视图上具有相应的 Insert 、Delete 、Update 或 Select 特权。
但是,如果您还不具有指定触发操作中某个 SQL 语句所需的特权的话,触发语
句可能仍会失败。当执行触发操作时,数据库服务器对于触发器定义中的每个
SQL 语句都检查您的特权,就像触发器的每个语句都被独立执行那样。关于执行
触发操作所需的特权的信息,请参阅执行触发操作的特权 。
触发器的性能影响
启动触发器的 INSERT 、DELETE 、UPDATE 和 SELECT 语句可能看起来执
行得比较慢,因为它们激活附加的 SQL 语句,且用户可能不知道正在发生其它
操作。
触发事件的执行时间取决于触发操作的复杂度以及它是否启动其它触发器。随着
级联触发器数目增加,时间也会增加。关于启动其它触发器的触发器的更多信
息,请参阅级联触发器。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 455
INSERT 事件和 DELETE 事件
表上的 INSERT 和 DELETE 事件由那些关键字和 ON table 子句定义,使用以
下语法。
在表上 INSERT 或 DELETE 事件

元素
描述
限制
语法
table 触发表的名称
必须在数据库中存在
标识符
当 INSERT 语句在其 INTO 子句中包含指定的 table (或 table 的同义词)
时, Insert 触发被激活。同样地,当 DELETE 语句在其 FROM 子句中包含指
定的 table (或 table 的同义词)时,Delete 触发器被激活。
如果 Insert 触发器指定的 table 是包含 Insert 子句的 MERGE 语句的目标表,
则 MERGE 语句也可以激活 Insert 触发器,同样地,如果 Delete 触发器指定的
table 是包含 Delete 子句的 MERGE 语句的目标表,则 MERGE 语句也可以激
活 Delete 触发器。
当 TRUNCATE TABLE 语句删除表的所有行时,它不会激活 Delete 触发器。如
果要对一个表定义启用的 Delete 触发器,而您不具有此表的 Alter 特权,则如果
您视图移除此表,即使 TRUNCATE 语句不是 Delete 触发器的触发事件,数据
库服务器仍会返回错误。(有关删除操作所需的自由访问权的更多信息,请参阅
TRUNCATE 语句。)
对于视图上的触发器,INSTEAD OF 关键字必须紧跟在指定触发事件类型的
INSERT 、DELETE 或 UPDATE 关键字之前,且视图(而不是表)的名称或同
义词必须跟在 ON 关键字之后。视图上的 INSTEAD OF 触发器部分描述定义
INSTEAD OF 触发事件的语法。
一个表上可以定义多个 Insert 触发器和多个 Delete 触发器。
如果您在表层次结构中的子表上定义触发器,且子表支持级联删除,则超级表上
的 DELETE 操作将激活子表上的 Delete 触发器。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 456
关于 Insert 触发器和 Delete 触发器的操作上的相关性和限制的信息,另请参阅
触发器的再进入一节。
UPDATE 事件
UPDATE 事件(和 SELECT 事件)可以包含可选的 column 列表、
UPDATE 事件

元素
描述
限制
语法
column
激发触发器的列
必须在触发表中存在
标识符
table
触发表的名称
必须数据库中存在
标识符
column 列表是可选的。如果您忽略 OF column 列表,则更改 table 的任何列都
将激活触发器。
OF column 子句对于视图上的 INSTEAD OF 触发器是无效的。
在两种情况下,触发表上的 UPDATE 可以激活触发器:

UPDATE 语句引用 column 列表中的任何列。

UPDATE 事件定义未指定 OF column 列表规范。
无论它更新 column 列表中的一列还是激活多列,触发 UPDATE 语句都只激活
Update 触发器一次。
如果指定没有 columns 列的触发器 table 是 MERGE 语句的目标表,或者如果
MERGE 语句的 Update 子句引用了Update 触发器的 column 列表中的列,则
MERGE 语句也可以激活 Update 触发器。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 457
定义多个 Update 触发器
一个表上的多个 Update 触发器不能包含相同的列。在以下示例中,trig3 在
items 表上是无效的,因为它的列列表包含 stock_num ,而 stock_num 是
trig1 中的触发列。
CREATE TRIGGER trig1 UPDATE OF item_num, stock_num ON items
REFERENCING OLD AS pre NEW AS post
FOR EACH ROW(EXECUTE PROCEDURE proc1());
CREATE TRIGGER trig2 UPDATE OF manu_code ON items
BEFORE(EXECUTE PROCEDURE proc2());
CREATE TRIGGER trig3 UPDATE OF order_num, stock_num ON items
BEFORE(EXECUTE PROCEDURE proc3());
当 UPDATE 语句尝试更新具有不同触发器的多个列时,触发列的列编号确定触
发执行的顺序。从编号最小的触发列开始执行,且按顺序一直执行到编号最大的
触发列。但是,如果在同一列或同一组列上设置了多个 Update 触发器,则不保
证触发器的执行顺序。
以下示例显示表 taba 具有四列(a 、 b 、 c 、 d):
CREATE TABLE taba (a int, b int, c int, d int);
将 trig1 定义为列 a 和 c 上的更新,将 trig2 定义为列 b 和 d 上的更新,
如以下示例所示:
CREATE TRIGGER trig1 UPDATE OF a, c ON taba
AFTER (UPDATE tabb SET y = y + 1);

CREATE TRIGGER trig2 UPDATE OF b, d ON taba
AFTER (UPDATE tabb SET z = z + 1);
以下示例显示 Update 触发器的触发语句:
UPDATE taba SET (b, c) = (b + 1, c + 1);
然后列 a 和 c 的 trig1 首先执行,列 b 和 d 的 trig2 随后执行。在此情况
中,触发器中列编号最小的是第 1 列(a),第二小的是第 2 列(b)。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 458
SELECT 事件
DELETE 和 INSERT 事件由那些关键字(和 ON table 子句),但是 SELECT
和 UPDATE 事件还支持可选的 column 列表。
SELECT 事件

元素
描述
限制
语法
column 激活触发器的列
必须在触发 table 中存

标识符
owner
table 的所有者
必须拥有 table
所有者名称
table
触发表的名称
必须在数据库中存在
标识符
如果您在同一个表上定义多个 Select 触发器,则每个触发器的 column 列表可以
是唯一的或者是另一个 Select 触发器的重复。
在这两种情况下,触发表上的 SELECT 可以激活触发器:

SELECT 语句引用 column 列表中的任何列。

SELECT 事件定义未指定 OF column 列表规范。
(但是,接下来的部分描述可能影响 SELECT 语句是否激活 Select 触发器的其
它情况。)
无论它指定 column 列表中的一列还是激活多列,触发 SELECT 语句都只激活
Select 触发器一次。
Select 触发器的操作不能在触发表上包含 UPDATE 、INSERT 或 DELETE 。
Select 触发器的操作可以在不是触发表的其它表上包含 UPDATE 、INSERT 或
DELETE 操作。以下示例在表的一列上定义 Select 触发器:
CREATE TRIGGER mytrig
SELECT OF cola ON mytab REFERENCING OLD AS pre
FOR EACH ROW (INSERT INTO newtab VALUES('for each action'));

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 459
您不能对视图上的 INSTEAD OF 触发器指定 SELECT 事件。
Select 触发器被激活时的情况
在这些情况中,在触发表上的查询激活 Select 触发器:

SELECT 语句是独立的 SELECT 语句。

SELECT 语句在选择列表中调用 UDR 中发生。

SELECT 语句是 Projection 列表中的子查询。

SELECT 语句是 FROM 子句中的子查询。

SELECT 语句在 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 调
用的 UDR 中发生。

SELECT 语句从表层结构中的超级表选择数据。在此情况中,SELECT
语句激活层次结构中的超级表和所有子查询的 Select 触发器。
有关不激活 Select 触发器的 SELECT 语句的信息,请参阅 Select 触发器未激活
时的情况。
独立 SELECT 语句
如果触发列出现在 SELECT 语句的 Projection 子句的选择列表中,则 Select 触
发器被激活。
例如,如果 Select 触发器被定义为当表 tab1 的列 col1 被选择时执行,则以
下两个独立 SELECT 语句都激活 Select 触发器;
SELECT * FROM tab1;
SELECT col1 FROM tab1;
选择列表中的 UDR 中的 SELECT 语句
如果 UDR 在其语句块中包含 SELECT 语句,则 Select 触发器被 UDR 激活,
且 UDR 还显示在 SELECT 语句的 Projection 子句的选择列表中。例如,假设
名为 my_rtn 的 UDR 在其语句块中包含此 SELECT 语句:
SELECT col1 FROM tab1;
限制假设以下 SELECT 语句在其选择列表中调用 my_rtn UDR :
SELECT my_rtn() FROM tab2;

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 460
当执行 my_rtn UDR 时,该 SELECT 语句激活表 tab1 的列 col1 上定义的
Select 触发器。
EXECUTE PROCEDURE 和 EXECUTE FUNCTION Call 的
UDR
如果 UDR 在其语句块中包含 SELECT 语句且 UDR 被 EXECUTE
PROCEDURE 或 EXECUTE FUNCTION 语句调用,则 Select 触发器被 UDR
激活。例如,假设名为 my_rtn 的用户定义过程在其语句块中包含以下 SELECT
语句:
SELECT col1 FROM tab1;
限制假设以下语句调用 my_rtn 过程:
EXECUTE PROCEDURE my_rtn();
当语句块中的 SELECT 语句被执行时,该语句激活表 tab1 的列 col1 上定义的
Select 触发器。
选择列表中的子查询
Select 触发器可以被 SELECT 语句的 Projection 子句的选择列表中出现的子查询
激活。
例如,如果 Select 触发器在 tab1 的 col1 上定义,则以下 SELECT 语句中的
子查询激活该触发器:
SELECT (SELECT col1 FROM tab1 WHERE col1=1), colx, col y FROM tabz;
SELECT 的 FROM 子句中的子查询
SELECT 的 FROM 子句中的表表达式可以是被不相关子查询引用的表上的触发
事件。在以下示例中,指定一个表表达式的子查询是定义在 tab1 的 col1 上的
Select 触发器的触发事件:
SELECT vcol FROM (SELECT FIRST 5 col1 FROM tab1 ORDER BY col1 )
vtab(vcol);

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 461
DELETE 或 UPDATE 的 WHERE 子句中的子查询
用 DELETE 语句 或 UPDATE 语句的 WHERE 子句中的子查询语法使用
Condition 的子查询不能是 Select 触发器的触发事件。在以下示例中,该子查询
不是定义在 tab1 的 col2 上的 Select 触发器的触发事件:
DELETE tab1 WHERE EXISTS
(SELECT col2 FROM tab1 WHERE col2 > 1024);
但是,在同一示例的 DELETE 操作,激活定义在 tab1 上的 Delete 触发器。tbl1
上的 Select 触发器不会被通过修改子查询的 FORM 子句中引用的表的 DELETE
语句中的子查询激活。
类似地,以下语句中的 WHERE 子句的子查询不是定义在 tab1 的 col3 上的
Select 触发器的触发事件:
UPDATE tab1 SET col3 = col3 + 10
WHERE col3 > ANY
(SELECT col3 from tab1 WHERE col3 > 1);
相同的示例会激活定义在 tbl 的 col3 上的 Update 触发器,但是此子查询不会更
改 Select 触发器。有关 Select 触发器的其它限制,请参阅 Select 触发器未激活
时的情况。
表层次结构中的 Select 触发器
GBase 8s 数据库中的子表继承超表上定义的 Select 触发器。当您从超级表中选择
时, SELECT 语句激活超级表上的 Select 触发器以及表层次结构中的子表上被
继承的 Select 触发器。
例如,假设表 tab1 是超级表且表 tab2 是表层次结构中的子表。如果 Select 触
发器 trig1 在表 tab1 上定义,则表 tab1 上的 SELECT 语句为表 tab1 中的各
行激活 Select 触发器 trig1,并为表 tab2 中的各行激活继承的 Select 触发器
trig1 。
如果您将 Select 触发器添加到子表,则该 Select 触发器不会覆盖该子表从其超
表继承的 Select 触发器,但是会增加子表上 Select 触发器的数量。例如,如果
Select 触发器 trig1 在超级表 tab1 中的列 col1 上定义,则子表 tab2 继承此触
发器。如果您在子表 tab2 的列 col1 上定义一个名为 trig2 的 Select 触发器,
和一个来自超表 tab1 的 col1 列的 SELECT 语句,则此 SELECT 语句为表

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 462
tab1 中的各行激活触发器 trig1 ,且为表 tab2 中的各行激活触发器 trig1 和
trig2 。
Select 触发器未激活时的情况
在某些情况下,触发表上的 SELECT 语句不激活 Select 触发器:

如果包含 SELECT 语句的子查询或 UDR 出现在除 FROM 子句或
Projection 子句的 SELECT 语句的其它任意子句中,则 Select 触发器不
被激活。

例如,如果子查询或 UDR 出现在 SELECT 语句的 WHERE 子句或
HAVING 子句中,则子查询或 UDR 中的 SELECT 语句不激活 Select
触发器。

如果 Select 触发器的触发操作调用包含触发 SELECT 语句的 UDR ,
则 UDR 中 SELECT 上的 Select 触发器不被激活。不支持级联选择触
发器。

如果 SELECT 语句在其 Projection 子句中包含内置聚集或用户定义的聚
集,则Select 触发器不被激活。例如,以下 SELECT 语句不会激活
tab1 的 col1 上定义的 Select 触发器:

SELECT MIN(col1) FROM tab1;

包含集合运算符(包括 INTERSECT 、MINUS 、EXCEPT 、UNION
或 UNION ALL)的 SELECT 语句不会激活 Select 触发器。

INSERT 的 SELECT 子句不激活 Select 触发器。

DELETE 或 UPDATEA 语句的 WHERE 子句中的子查询不会激活
DELETE 或 UPDATE 语句正在更新的同一表上的 Select 触发器。

如果 SELECT 的 Projection 子句包含 DISTINCT 或 UNIQUE 关键
字,则 SELECT 语句不会激活 Select 触发器。

滚动游标上不支持 Select 触发器。

如果 SELECT 语句引用远程触发表,则 Select 触发器在远程数据库服
务器上不被激活。

查询的 ORDER BY 列表中的列不激活 Select 触发器(也不激活任何其
它触发器),除非它们也列在 Projection 子句中。
最后一条限制的例外是 Select 触发器可以被 FROM 子句的子查询列表中的
ORDER BY 列表中的列激活,无论该相同的列是否出现在 Projection 子句中。在
以下示例中,在 ORDER BY 子句中包含 col1 的表表达式(而不是在 Projection

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 463
子句中的选择列表的表表达式)是 tab1 的 col1 上定义的 Select 触发器的触发
事件:
SELECT vcol FROM (SELECT col2 FROM tab1 ORDER BY col1 ) vtab(vcol);
Action 子句
Action 子句定义触发器被激活时要执行的 SQL 语句。对于表上的触发器,在
Action 子句中可以有三个部分:BEFORE 、AFTER 和 FOR EACH ROW。

在数据库服务器执行触发 DML 操作之前,BEFORE 操作会对每个触发
事件执行一次。

在触发语句的上下文中,表上的操作执行完毕后,AFTER 操作也会对每
个触发 DML 事件执行一次。

会对 DML 操作中的插入、更改、删除或选择的每一行执行 FOR EACH
ROW 操作,在每一行上的 DML 操作执行之后,但是在数据库服务器将
数据写入日志和表之前。
如果一个表具有被同一触发事件激活的多个触发器,则不保证执行触发的顺序,
但是所有的 BEFORE 触发操作都在任何 FOR EACH ROW 触发操作之前执行,
并且所有的 AFTER 触发操作在 FOR EACH ROW 触发操作后执行。
当您在视图上定义 INSTEAD OF 触发器时,不支持 BEFORE 和 AFTER 关键
字,但是 Action 子句的 FOR EACH ROW 部分是有效的。有关在视图上指定触
发操作的语法,请参阅视图上的 INSTEAD OF 触发器章节。
Action 子句具有以下语法。
Action 子句

要使触发器对表产生作用,则您必须定义至少一个触发操作,使用 BEFORE 、
FOR EACH ROW 或 AFTER 关键字指示何时发生相对于触发事件的执行的操
作。
您可以在单个触发器上为这三个选项中的任何一个或所有三个指定操作,但是必
须首先指定任何 BEFORE 操作列表,并且最后指定任何 AFTER 操作列表。有

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 464
关当 REFERENCING 子句也被指定时的 Action 子句的更多信息,请参阅相关的
表操作。
BEFORE 操作
在触发语句执行之前,BEFORE 触发器操作列表只执行一次。即使触发语句不处
理任何行,数据库服务器仍然执行 BEFORE 触发器操作。
FOR EACH ROW 操作
处理触发表的一行后,数据库服务器执行 FOR EACH ROW 触发器操作列表的所
有语句;此循环对触发语句处理的每一行重复执行。(但是如果触发语句不插
入、删除、更新或选择任何行,则数据库服务器不执行 FOR EACH ROW 触发操
作。)
Select 触发器的 FOR EACH ROW 操作列表对于行的每个实例执行一次。例如,
同一行可以在结合两个表的查询结果中出现多次。有关引用触发语句过程中指定
的值的 FOR EACH ROW 操作的更多信息,请参阅 REFERENCING 子句 。
正如触发器上的限制中所述的那样,对于对应于触发器事件类型的 DM 语句,并
行数据的处理在 FOR EACH ROW 触发器操作中是禁用的。例如,数据库服务器
不会在 Update 触发器的 Action 子句的 FOR EACH ROW 部分的 UPDATE 语
句中应用 PDQ ,也不会在 Delete 触发器的 Action 子句的 FOR EACH ROW
部分的 DELETE 语句中应用。PDQ 处理过程上的限制不适用于 Action 子句的
BEFORE 或 AFTER 部分的 DML 语句。
AFTER 操作
触发语句的操作完成后,指定的 AFTER 触发器操作执行一次。如果触发器语句
不处理任何行,则 AFTER 触发器操作仍将执行。
多个触发器的操作
当 UPDATE 或 MERGE 语句激活多个触发器时,触发操作合并。假设 taba 具
有列 a 、b 、c 和 d,如该示例所示:
CREATE TABLE taba (a INT, b INT, c INT, d INT);

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 465
接下来。假设您在列 a 和 c 上定义 trig1,在列 b 和 d 上定义 trig2 。如果
两个触发器都指定BEFORE 、FOR EACH ROW 和 AFTER 操作,则按以下顺序
执行触发器操作:
1. 触发器的 BEFORE 操作列表(a 、 c)
2. 触发器的 BEFORE 操作列表(b 、d)
3. 触发器的 FOR EACH ROW 操作列表(a 、c)
4. 触发器的 FOR EACH ROW 操作列表(b、 d)
5. 触发器的 AFTER 操作列表(a 、 c)
6. 触发器的 AFTER 操作列表(b 、 d)
数据库服务器将由同一个触发语句激活的所有触发器视为单个触发器。且触发操
作是合并操作列表。控制触发器操作的所有规则适用于作为单个列表的合并列
表,且两个原始触发器之间没有区别。
确保行顺序的独立性
在 FOR EACH ROW 触发操作列表中,结果可能取决于正在处理的行的顺序。通
过以下建议,您可以确保结果是独立于行顺序的:

避免在 FOR EACH ROW 部分中选择触发表。
如果触发语句影响触发表中的多个行,则 FOR EACH ROW 部分中的
SELECT 语句的结果随着处理的每一行而变化。该条件也适用于任何级
联触发器。请参阅级联触发器。

在 FOR EACH ROW 部分中,避免使用从触发表的当前行得到的值更新
表。
如果触发操作多次修改表中的任何行,则该行的最终结果取决于触发表中
行处理的顺序。

避免在同一个 FOR EACH ROW 触发操作(包括任何级联触发操作)中
的另一个语句选择的 FOR EACH ROW 部分中修改表。
如果 FOR EACH ROW 操作修改表,则当触发器随后的操作引用表时,该更改可
能不完整。在此情况中,结果可能不同,这取决于处理行的顺序。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 466
数据库服务器不实施规则以避免这些情况,因此如果这样做或限制触发操作可以
选择的表的集合。而且,大多数触发操作的结果是独立于行顺序的。因此,您负
责确保触发操作的结果独立于行顺序。
REFERENCING 子句
任何事件的 REFERENCING 子句声明可以用于触发表中限定列值的相关名(对
于 Update 触发器,两个相关名称)。这些名称启用 FOR EACH ROW 操作以引
用触发事件结果中的新值。
它们还启用 FOR EACH ROW 操作以引用触发事件修改前触发表中存在的旧列
值。
如果该触发操作同时包括了 INSERT 语句和 BEFORE WHEN 或 AFTER WHEN
关键字,则相关名无效。此限制对指定 FOR EACH ROW 关键字不含 BEFORE
或 AFTER 关键字或者不包含 INSERT 语句的触发操作没有影响。
此处为 CREATE TRIGGER 语句描述的 REFERENCING 子句语法在定义例程的
CREATE FUNCTION 和 CREATE PROCEDURE 语句中是可用的,它提供
CREATE FUNCTION 或 CREATE PROCEDURE 语句也包括 FOR table_object
子句以指定表或视图的 FOR EACH ROW 操作可以调用触发例程。
用于删除的 REFERENCING 子句
Delete 触发器的 REFERENCING 子句可以为列中要删除的值声明相关名称。
用于删除的 REFERENCING 子句

元素
描述
限制
语法
correlation 此处为满足在触发器操作中使
用的旧列值声明的名称
( correlation.column)
在此 CREATE TRIGGER
语句中必须唯一
标识

correlation 是在触发语句执行前,用于触发表中列值的限定符。correlation 在
FOR EACH ROW 触发操作列表中的作用域中。请参阅相关的表操作。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 467
要在触发操作中使用相关名称以引用旧的列值,请以相关名称和句号(.)作为列
名的前缀。例如,如果 NEW correlation 是 post ,请将列 fname 的新值引用为
post.fname。
如果触发器事件是 DELETE 语句,则使用 new 相关名作为限定符会产生错误,
因为咋i 该行被删除后该列没有值。要了解控制使用相关名称的规则,请参阅在
触发操作中使用相关名称。
只要您定义了 FOR EACH ROW 触发操作,就可以为删除使用 REFERENCING
子句。
用于插入的 REFERENCING 子句
Insert 触发器的 REFERENCING 子句可以为列中要插入的值声明相关名称。
用于插入的 REFERENCING 子句

元素
描述
限制
语法
correlation 此处为满足在触发器操作中使用
的新列值声明的名称
( correlation.column)
在此 CREATE
TRIGGER 语句中必须
唯一
标识

correlation 是在执行触发语句后用于新列值的名称。其引用作用域仅限于 FOR
EACH ROW 触发操作列表;请参阅相关的表操作。要使用相关名称,请在列名
前面加上 correlation 名称和句号( . )。因此,如果 NEW correlation 名称是
post ,请将列 fname 的新值称为 post.fname。
如果触发事件是 INSERT 语句,则使用 old correlation 名称作为限定符会产生错
误,因为插入行前不存在值。要了解控制如何使用相关性的规则,请参阅在触发
操作中使用相关名称。只有您定义了 FOR EACH ROW 触发操作,就可以使用
INSERT REFERENCING 子句。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 468
以下示例说明 INSERT REFERENCING 子句的用法。对于插入到 table1 中的每一
行,该示例将一行插入到 backup_table1 中。插入到 backup_table1 的 col1
和 col2 中的值是刚插入到 table1 中的值的精确副本。
CREATE TABLE table1 (col1 INT, col2 INT);
CREATE TABLE backup_table1 (col1 INT, col2 INT);
CREATE TRIGGER before_trig
INSERT ON table1 REFERENCING NEW AS new
FOR EACH ROW
(
INSERT INTO backup_table1 (col1, col2)
VALUES (new.col1, new.col2)
);
如以上示例所示,INSERT REFERENCING 子句使您能够引用触发操作生成的数
据值。
用于更新的 REFERENCING 子句
Update 触发器的 REFERENCING 子句可以为列中原始值和已更改的值声明相关
名称。
用于更新的 REFERENCING 子句

元素
描述
限制
语法
correlation 您在此为在触发器操作中使用
的旧的或新的列值声明的名称
(correlation.column)
在此 CREATE TRIGGER
语句中必须唯一
标识

OLD correlation 是执行触发语句前触发表中的列值的名称;NEW correlation 标
识执行触发语句后的相应值。
您在此声明的 correlation 名称的引用作用域只限于 FOR EACH ROW 触发器操
作列表中。请参阅相关的表操作。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 469
要引用新的或旧的列值,请以 correlation 名称和句号(. )作为列名的前缀。例
如,如果 new correlation 名称是 post ,您可以将列 fname 中的新值引用为
post.fname。
如果触发器事件是 UPDATE 语句,则您可以同时定义 old 和 new correlation 名
称以引用触发 UPDATE 语句之前和之后的列值。要了解控制使用 correlation 名
称的规则,请参阅在触发操作中使用相关名称。
只有您定义了 FOR EACH ROW 触发操作,就可以使用 UPDATE
REFERENCING 子句。
用于选择的 REFERENCING 子句
Select 触发器的 REFERENCING 子句可以为列中的值声明相关名称。
用于选择的 REFERENCING 子句

元素
描述
限制
语法
correlation 您在触发操作中此为旧或新列
值声明的名称
(correlation.column)
在此 CREATE TRIGGER
语句中必须是唯一的
标识

该子句具有与用于删除的 REFERENCING 子句相同的语法。您在此声明的
correlation 名称的引用作用域只限于 FOR EACH ROW 触发操作列表中。请参阅
相关的表操作。
您可与通过在列名前加上相关名称和句号(.)使用 correlation 名称以引用 old
列值。例如,如果 old correlation 名称是 pre ,则您可以将列 fname 的旧值引
用为 pre.fname。
如果触发事件是 SELECT 语句,则使用 new correlation 名称作为限定符会产生
错误,因为在选择该列后该列不具有 new 值。要了解控制使用相关名称的规则,
请参阅在触发操作中使用相关名称。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 470
只有您定义了 FOR EACH ROW 触发操作,就可以使用 SELECT
REFERENCING 子句。
相关的表操作
使用 Correlated Trigger Action 子句定义当触发事件激活表上的触发器时作为触发
操作执行的 SQL 语句。
相关的表操作

如果 CREATE TRIGGER 语句包含 INSERT REFERENCING 子句、DELETE
REFERENCING 子句、UPDATE REFERENCING 子句或者 SELECT
REFERENCING 子句,则您必须在操作子句中包含 FOR EACH ROW 触发操作
列表。您还可以包含 BEFORE 和 AFTER 触发操作列表,但是它们是可选的。
有关 BEFORE 、FOR EACH ROW 和 AFTER 触发操作列表的信息,请参阅
Action 子句。
触发操作
触发操作指定触发器被激活时,执行 SQL 语句的列表。Action 子句的
BEFORE 、FOR EACH ROW 和 AFTER 部分可以指定同一触发器的不同触发操
作列表。
触发操作
对于表上的触发器。触发操作由可选的 WHEN 条件和操作语句构成。您可以为
每个 WHEN 子句指定触发操作列表,或者如果您不包含 WHEN 子句的话可以
指定单个列表(由一个或多个触发操作构成)。
当 CREATE TRIGGER 语句定义新的触发器时,在触发操作或触发事件的定义中显
式引用的数据库对象(例如表、列和 UDR )必须存在。
注意: 当您在 WHEN 条件中或操作语句中指定日期表达式时,请确保对年份指
定四位数字而不是两位数字。有关缩写年份的更多信息,请参阅 GBase 8s SQL
参考指南 中关于 DBCENTURY 的描述。该文档还描述了环境变量设置如何影

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 471
响某些数据库对象的行为。与分片表达式、检查约束、和 UDR 类似,触发器与
环境变量的创建时间设置一起存储在系统目录表中,环境变量可能影响诸如
WHEN 条件之类的表达式求值。当对那些数据库对象中的表达式求值时,数据库
服务器忽略对这些设置的所有后续更改。
WHEN 条件
WHEN 条件使触发操作依赖于测试的结果。当您在触发操作中包含 WHEN 条件
时,仅当条件所得的值为 true 时,触发操作列表中的语句才执行。如果 WHEN
条件求值为 false 或 unknown ,则触发操作列表中的语句不执行。
如果触发操作在 FOR EACH ROW 部分中,则其条件对每一行求值,例如,仅当
WHEN 子句为 true 时以下触发器中的触发操作才执行:
CREATE TRIGGER up_price
UPDATE OF unit_price ON stock
REFERENCING OLD AS pre NEW AS post
FOR EACH ROW WHEN(post.unit_price > pre.unit_price * 2)
(INSERT INTO warn_tab VALUES(pre.stock_num, pre.order_num,
pre.unit_price, post.unit_price, CURRENT));
在 WHEN 条件内执行的 SPL 例程与在数据库操纵语句中调用的 UDR 具有相
同的限制。也就是说,SPL 例程不能包含某些 SQL 语句。有关语句受限制的信
息,请参阅在数据操纵语句中 SPL 例程的限制。
操作语句
触发操作语句可以是 INSERT 、DELETE 、UPDATE 、EXECUTE FUNCTION
或 EXECUTE PROCEDURE 语句。如果操作列表包含多个语句,并且 WHEN 添
加满足(或缺失),则这些语句按它们在列表中出现的顺序执行。
作为触发操作的 UDR
用户定义的函数和过程包括触发例程可以是触发操作。FOR EACH ROW 子句的
操作列表可以包含调用 mi_trigger*( ) 函数的 UDR 。只有 GBase 8s 中的触发
例程的上下文中的触发操作能被调用。有关触发例程的语法和调用内容的限制,
请参阅 REFERENCING 和 FOR 子句。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 472
您可以使用 EXECUTE FUNCTION 语句调用任何用户定义的函数或触发器函
数。使用 EXECUTE PROCEDURE 语句调用热河用户定义的过程或触发器过程。
在 Boolean 表达式有效的上下文中,Boolean 运算符 SELECTING 、
INSERTING 、DELETING 和 UPDATING 在触发例程中都有效,且在其它在触
发操作语句调用的 UDR 中也是有效的。如果触发事件与符合运算符名称的
DML 操作相匹配,则这些运算符返回 TRUE('t');否则返回 FALSE('f')。一
个触发例程可以设计成为不同种类的触发事件执行不同触发操作,使用这些
Boolean 运算符执行与触发器类型相适合的程序块。
有关使用 SPL 例程作为触发操作的限制,请参阅 SPL 例程的规则和触发器和
SPL 例程。
实现一致性结果
要保证触发语句对于有触发操作或没有时都返回相同的结果,请确保 BEFORE
和 FOR EACH ROW 部分中的触发操作不修改以下子句中引用的任何表:

WHERE 子句

UPDATE 语句中的 SET 子句

SELECT 子句

多行 INSERT 语句中的 EXECUTE PROCEDURE 子句或 EXECUTE
FUNCTION 子句 。
声明 SQL 的关键字作为相关名称
如果您在触发操作列表中的以下任何子句中使用 INSERT 、DELETE 、UPDATE
或 EXECUTE 关键字作为 correlation 标识符,则必须使用所有者名称和/或表
名称限定它们。

SELECT 语句的 FROM 子句

EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句的 INTO 子句

GROUP BY 子句

UPDATE 语句的 SET 子句
当您在触发操作中包含这些关键字时,如果这些关键字未被限定,则会产生语法
错误。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 473
如果您使用关键字作为列名,则必须使用表名限定它;例如 table.update。如果
表名称和列名称都是关键字,则必须使用所有者名称限定它们(例如,
owner.insert.update)。如果所有者名称、表名称和列名称都是关键字,则必须用
引号将所有者名称引起来;例如 'delete'.insert.update。(这些是将保留字作为标
识符的一般规则,而不是触发器的特例。如果避免使用 SQL 的关键字作为标识
符,则您的代码会更易阅读和维护。)
唯一的例外是这些关键字是列表汇总的第一个表或列名称时,且您没有限定它
们。例如,不需要限定以下语句中的 delete ,因为它是 INTO 子句列出的第一
列:
CREATE TRIGGER t1 UPDATE OF b ON tab1
FOR EACH ROW (EXECUTE PROCEDURE p2() INTO delete, d);
在以下语句显示的示例中,您必须限定列名称或表名称:

SELECT 语句的 FROM 子句
CREATE TRIGGER t1 INSERT ON tab1
BEFORE (INSERT INTO tab2 SELECT * FROM tab3, 'owner1'.update);

EXECUTE PROCEDURE 语句的 INTO 子句
CREATE TRIGGER t3 UPDATE OF b ON tab1
FOR EACH ROW (EXECUTE PROCEDURE p2() INTO
d, tab1.delete);
视图上的 INSTEAD OF 触发器在其已触发的操作中不能包含 EXECUTE
PROCEDURE INTO 语句。

SELECT 语句的 GROUP BY 子句
CREATE TRIGGER t4 DELETE ON tab1
BEFORE (INSERT INTO tab3 SELECT deptno, SUM(exp)
FROM budget GROUP BY deptno, budget.update);

UPDATE 语句的 SET 子句
CREATE TRIGGER t2 UPDATE OF a ON tab1
BEFORE (UPDATE tab2 SET a = 10, tab2.insert = 5);
在触发操作中使用相关名称
当您在触发操作中使用相关名称时应用这些规则:

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 474

您可以在 FOR EACH ROW 触发操作列表的 SQL 语句中和 WHEN 条
件中为旧列和新列值使用相关名称。

同一表上的多个触发器的 WHEN 条件和 FOR EACH ROW 子句可以在
触发器和触发器例程的 REFERENCING 子句中使用不同的相关的变量来
引用同一列的值。

旧的和新的相关性名称引用触发语句影响的所有行。

在 GROUP BY 、SET 或 COUNT DISTINCT 子句中不能使用相关性名
称限定列名称。

相关性名称的引用作用域是整个触发器定义。该作用域是静态确定的,这
意味着它限制于触发器定义;它不包含作为触发操作的 UDR 中的表名称
限定的级联触发器或列,期望在 FOR EACH ROW 子句中调用触发器的
例程。
有关在触发器例程中使用相关名称的其它信息,请参阅 SPL 例程的规则。
何时使用相关性名称
在 FOR EACH ROW 列表的 SQL 语句中,您必须使用旧的或新的相关性名称限
定对触发表中的列的引用,触发该语句有效独立于触发操作。
换句话说,如果 FOR EACH ROW 触发操作列表中的列名称未用相关性名称限
定,则即使使用触发表名称限定它,仍会像该语句独立于触发操作那样解释它。
对于非限定的列名称,不特别搜索触发表的定义。
例如,假设以下 DELETE 语句是触发器的 FOR EACH ROW 部分中的触发部分:
DELETE FROM tab1 WHERE col_c = col_c2;
要使该语句有效,则 col_c 和 col_c2 都必须是来自 tab1 的列。如果打算使用
col_c2 作为触发表中某列的相关性引用,则必须使用旧的或新的相关性名称限定
它。如果 col_c2 不是 tab1 中的列且未用旧的或新的相关性名称限定,则您将得
到错误。
在有效独立于触发操作的语句中,没有 correlation 限定符的列名称引用数据库中
的当前值。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 475
下一个示例中,在触发器 t1 的触发操作中,相关子查询的 WHERE 子句中的 mgr
是触发表中的非限定列。在此情况中,mgr 引用 empsal 中的当前列值,因为
INSERT 语句有效独立于触发操作。
CREATE DATABASE db1;
CREATE TABLE empsal (empno INT, salary INT, mgr INT);
CREATE TABLE mgr (eno INT, bonus INT);
CREATE TABLE biggap (empno INT, salary INT, mgr INT);

CREATE TRIGGER t1 UPDATE OF salary ON empsal
AFTER (INSERT INTO biggap SELECT * FROM empsal WHERE
salary <
(SELECT bonus FROM mgr WHERE eno = mgr));
在触发操作中,来自触发表的非限定列名引用当前列值,但是触发器声明必须有
效独立于触发操作。
限定值与非限定值的比较
下面的表总结了在发生不同触发器事件后用 old 或 new 相关名限定 column 名
称时,检索的值。
触发事件
old.column
new.column
INSERT
无值(错误)
插入的值
UPDATE (column updated)
初始值
当前值(U)
UPDATE (column not updated) 初始值
当前值(N)
DELETE
初始值
无值(错误)
SELECT
初始值
无值(错误)
当相关性名称没有值是,只要 SQL 或 SPL 语句引用未定义的相关名称执行时而
不是在声明相关性名称时,会发出错误,当您读取上一个表时引用以下键。
术语 含义
初始值 触发事件前的值
当前值 触发事件后的值

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 476
(N) 不能被触发操作更改
(U) 可以被触发语句更新;更新的值可能因为前面的触发操作而与初始值
不同。
在 FOR EACH ROW 触发操作列表外,您不能使用旧的或新的相关名限定来自触
发表的列;它总是引用数据库中的当前值。
创建触发器时,触发操作列表中的语句使用任何有效的排列顺序,即使执行触发
器操作时有效的排列不同。请参阅 SET COLLATION 语句 以获取关于如何指定
与 DB_LOCALE 所指定的不同的排列顺序。
触发器的再进入
在某些情况下触发器可以是再进入的。在这些情况中,触发操作可以引用触发
表。换句话说,触发事件和触发操作都在同一个表上操作。下表总结了触发器可
以是再进入的情况和触发器不能是再进入的情况:

Update 触发器的触发操作不能是触发事件更新的表的 INSERT 或
DELETE 。

同样,Update 触发器的触发器操作不能是对触发器事件更新的列的
UPDATE 。(但是 Update 触发器的触发器操作可以更新未由触发器事
件更新的列。)
例如,假设以下 UPDATE 语句,更新 tab1 的列 a 和 b ,是触发语
句:
UPDATE tab1 SET (a, b) = (a + 1, b + 1);
现在考虑以下示例中的触发操作。第一个 UPDATE 语句可以是有效的触
发操作,但是第二个不是,因为它再次更新 b 列。
UPDATE tab1 SET c = c + 1; -- OK
UPDATE tab1 SET b = b + 1; -- INVALID

如果触发器具有 UPDATE 事件,则触发操作可以是带有 INTO 语句
(引用触发事件更新的列或触发表中的任何其它列)的 EXECUTE
PROCEDURE 或 EXECUTE FUNCTION 语句。
当 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句是触发操作
时 UPDATE 触发器的 INTO 子句仅在 FOR EACH ROW 触发操作中有
效,并且出现在 INTO 子句中的列名必须来自触发表。
以下语句说明了 INTO 子句的正确用法:

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 477
CREATE TRIGGER upd_totpr UPDATE OF quantity ON items
REFERENCING OLD AS pre_upd NEW AS post_upd
FOR EACH ROW(EXECUTE PROCEDURE
calc_totpr(pre_upd.quantity,post_upd.quantity,
pre_upd.total_price) INTO total_price);
INTO 关键字之后的列必须在触发列表中,但是不需要被触发事件更新。
当 INTO 子句出现在 EXECUTE PROCEDURE 或 EXECUTE
FUNCTION 语句中时,当从 UDR 返回值时,数据库服务器立即用该值
更新指定的列。

如果触发器具有 INSERT 事件,则触发操作不能是引用触发表中的列的
INSERT 或 DELETE 语句。

如果触发器具有 INSERT 事件,则触发操作可以是引用触发表中的列的
UPDATE 语句,但是该列不能是触发器事件向其提供值的列。
如果触发器具有 INSERT 事件,并且触发器操作更新触发表,则两个语
句中的列必须互斥。例如,假设触发语句为表 tab1 的列 cola 和 colb
插入值:
INSERT INTO tab1 (cola, colb) VALUES (1,10);
现在考虑以下触发操作。第一个 UPDATE 是有效的,但是第二
个无效。因为即使触发事件已经为列 colb 提供了值,它仍然更
新列 colb :
UPDATE tab1 SET colc=100; --OK
UPDATE tab1 SET colb=100; --INVALID

如果触发器具有 INSERT 事件,则触发操作可以是带有 INTO 子句(引
用触发事件提供的列或触发事件未提供的列)的 EXECUTE
PROCEDURE 或 EXECUTE FUNCTION 语句。
当 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句是触发操作
时,仅当触发操作出现在 FOR EACH ROW 列表中时,您可以为
INSERT 触发器指定 INTO 子句。在此情况中,INTO 子句只能包含来自
触发表的列名称。
以下语句说明了 INTO 子句的有效用法:
CREATE TRIGGER ins_totpr INSERT ON items
REFERENCING NEW AS new_ins

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 478
FOR EACH ROW (EXECUTE PROCEDURE calc_totpr
(0, new_ins.quantity, 0) INTO total_price);
INTO 关键字之后的列可以是触发事件提供的触发列表中的列,或是触发
事件未提供的触发表中的事件。
当 INTO 子句出现在 EXECUTE PROCEDURE 或 EXECUTE
FUNCTION 语句中时,数据库夫服务器立即用从 UDR 返回的值更新指
定的列。

如果触发操作是 SELECT 语句,则 SELECT 语句可以引用触发表。
SELECT 语句可以是以下实例中的触发操作:
o
SELECT 语句出现在 WHERE 子句的子查询中或出现在触发操作
语句中。
o
触发操作是 UDR ,且 SELECT 语句出现在 UDR 中。
再进入和级联触发器
触发器不能再进入的情况中递归应用于所有的级联触发器。它被认为是初始触发
器的一部分。特别地,该规则表示级联触发器不能更新原始触发语句更新的触发
表中的任何列,包括该语句影响的任何非触发列。例如,假设此 UPDATE 语句
是触发语句:
UPDATE tab1 SET (a, b) = (a + 1, b + 1);
在下一个示例的级联触发器中,trig2 在运行时失败,因为它引用触发 UPDATE
语句更新的列 b :
CREATE TRIGGER trig1 UPDATE OF a ON tab1-- Valid
AFTER (UPDATE tab2 SET e = e + 1);

CREATE TRIGGER trig2 UPDATE OF e ON tab2-- Invalid
AFTER (UPDATE tab1 SET b = b + 1);
现在考虑以下 SQL 语句,当执行最终的 UPDATE 语句时,列 a 被更新且触发
器 trig1 被激活。
触发操作再次用 EXECUTE PROCEDURE INTO 语句更新列 a 。
CREATE TABLE temp1 (a INT, b INT, e INT);
INSERT INTO temp1 VALUES (10, 20, 30);

CREATE PROCEDURE proc(val iINT) RETURNING INT,INT;

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 479
RETURN val+10, val+20;
END PROCEDURE;

CREATE TRIGGER trig1 UPDATE OF a ON temp1
FOR EACH ROW (EXECUTE PROCEDURE proc(50) INTO a, e);

CREATE TRIGGER trig2 UPDATE OF e ON temp1
FOR EACH ROW (EXECUTE PROCEDURE proc(100) INTO a, e);

UPDATE temp1 SET (a,b) = (40,50);
该级联触发器示例有几个问题。首先,更新列 a 是否会再次激活触发器 trig1 ?
答案是否定的。因为触发器已被激活,它没有被再次激活。如果触发操作是
EXECUTE PROCEDURE INTO 或 EXECUTE FUNCTION INTO 语句,只有那些
从更新的列到之后(在触发器级联中)在该表中互斥的列上定义的触发器才被激
活。其它触发器被忽略。
该示例产生的另一个问题是触发器 trig2 是否被激活。答案是肯定的。触发器
trig2 在列 e 上定义。直到现在,表 temp1 中的列 e 尚未被修改。触发器 trig2
被激活。
该示例产生的最后一个问题是执行 trig2 中您的触发操作后触发器 trig1 和 trig2
是否被激活。答案是否定的。两个触发器都不会被激活。在此之前列 a 和 e 已
被更新一次,触发器 trig1 和 trig2 已被执行一次。数据库服务器忽略这些触发
器且不激活它们。关于级联触发器的更多信息,请参阅级联触发器。
正如前面提到的,视图上的 INSTEAD OF 触发器在其它触发器操作中不能包含
EXECUTE PROCEDURE INTO 语句。而且,如果两个视图分别具有带有已定义
的操作(在其它视图上执行插入操作)的 INSERT INSTEAD OF 触发器的话,会
产生错误。
SPL 例程的规则
除了触发器的再进入中列出的规则外,以下规则适用于指定为触发操作的 SPL 例
程:

在只希望有一行的上下文中,SPL 例程不能是游标函数(返回多行的函
数)。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 480

在 SPL 例程中不能使用旧的或新的相关性名称,除非 CREATE
FUNCTION 或 CREATE PROCEDURE 语句包含了将 UDR 定义为触发
例程的 REFERENCING 子句。如果您需要在例程中使用相应的值,则必
须将它们传递为参数。例程应答独立于触发器,且旧的或新的相关性名称
在触发器外不具有任何意义。

触发器例程必须包含可以为触发器例程中 SPL 语句可以引用的 OLD 或
NEW 列值声明相关名称的 REFERENCING 子句。

触发例程必须包含指定本地数据库中的表或视图的名称的 FOR
table_object 子句,其触发器可以调用此例程。该触发操作不能调用没有
指定触发表或视图的触发器例程。

只有在 Triggered Action 列表的 FOR EACH ROW 部分中调用的触发器
例程才能直接操作在触发器的或触发器例程的 REFERENCING 子句中定
义的旧的或新的相关名称。

触发器例程只能在触发器定义中 Triggered Action 列表的 FOR EACH
ROW 部分调用。

OLD 或 NEW 值的相关变量可以出现在 SPL 的 IF 语句和 CASE 表达
式中。

只有 NEW 值的相关变量可以在引用相关变量的 LET 表达式的左边。
在这种情况中,SPL 例程的 FOR 子句必须指定表(而非视图),并且
调用 SPL 例程的操作的触发器不能是 INSTEAD OF 触发器。

OLD 和 NEW 值可以在 LET 表达式的右边。

只用 FOR EACH ROW 子句中调用的触发器例程可以使用 Boolean 运算
符SELECTING 、INSERTING 、DELETING 和 UPDATING。如果触发
事件符合由相同名称的运算符引用的 DM 操作,则返回 TRUE('t'),
否则返回 FALSE('f')。

SPL 的 IF 语句和 SQL 的 CASE 表达式可以指定这些运算符为触发例
程中的条件。

触发器例程必须用 SPL 语句编写。它们不能使用外部语言编写,例如 C
或 Java™ 语言,但是触发器例程可以包含外部语言的调用,例如用于触
发器内省的 mi_trigger 应用程序接口。

触发器例程不能引用保存点。触发操作对数据值或数据库结构的更改必须
整体提交或回滚。 GBase 8s 在触发器例程中不支持 ROLLBACK TO
SAVEPOINT 语句用于触发操作的部分回滚。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 481
有关 mi_trigger API 的更多信息,请参阅 GBase 8s DataBlade API 程序员指南
和 GBase 8s DataBlade API 函数参考 。
当您使用 SPL 例程作为触发操作时,除非执行该例程,否则例程引用的数据库对
象不被检查。
另请参阅 触发器和 SPL 例程 中的 SPL 限制。
执行触发操作的特权
如果您不是此触发器的所有者,但是触发器所有者的访问特权包含 WITH
GRANT OPTION ,则除了您子句对每个 SQL 语句的特权外还继承所有者(具有
授权选项)的特权。如果触发器操作是 UDR ,则您需要 UDR 上的 Execute 特
权,或者触发器所有者必须具有授权选项的 Execute 特权。
重要: 作为安全预防措施,用户仅保留角色(但是并不是单独授予用户或作为
PUBLIC 组成员的角色)的自由访问权不能通过触发操作或通过触发例程提供对
当前数据库以外的表的访问。
然而,当执行 UDR 时,您不继承触发器所有者的特权;相反,您接收随 UDR
授予的特权,它取决于此例程是 DBA 特权例程还是所有者特权 UDR:

DBA 特权 UDR 的特权
当使用 DBA 关键字注册 UDR ,且您被授予了 UDR 上的 Execute 特
权时,数据库服务器自动为您授予临时 DBA 特权,这些特权仅当您执
行 UDR 时才可用。

所有者特权 UDR 的特权
如果创建没有 DBA 关键字的 UDR,但是 UDR 的所有者对于基础数据
库对象上的必要特权具有 WITH GRANT OPTION 关键字,当您被授予
UDR 的 Execute 特权时,您会继承这些特权。
对于没有 DBA 特权的 UDR ,UDR 引用的所有非限定数据库对象都被 UDR
所有者的名称隐式限定。
如果 UDR 所有者没有 WITH GRANT OPTION 特权,则当 UDR 执行您在基础
数据库对象上具有原始特权。有关 SPL 例程上的更多信息,请参阅 GBase 8s
SQL 教程指南 。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 482
不具有 INSTEAD OF 触发器的视图只有过Select (具有授权选项)特权。但
是,如果在它上面创建 INSTEAD OF 触发器,则在触发器创建期间该视图具有
Insert (具有授权选项)特权。视图所有者现在只能为其它人授予 Select 和
Insert 特权。这对触发操作是独立的。不必获取过程或函数上的 Execute(具有授
权选项)特权。缺省情况限,在操作列表中的每个 UDR 上授予 Execute(具有
授权选项)特权。
您可以使用具有触发器的角色。与角色相关的语句(CREATE ROLE 、DROP
ROLE 、GRANT 、REVOKE 和 SET ROLE)和 SET SESSION
AUTHORIZATION 语句在触发操作调用的 UDR 中有效。当执行触发器时,用
户通过启用角色或通过 SET SESSION AUTHORIZATION 语句已经获取的特权不
会被放弃。
在复杂的视图(具有来自多个表的列的视图)上,只有所有者或 DBA 可以创建
INSTEAD OF 触发器。当创建触发器时,所有者接收 Select 特权。只有获取必需
的 Execute 特权后,视图所有者才能为其它用户授予特权。当删除复杂视图上的
触发器时,所有这些特权都被撤销。
创建任何人都能使用的触发操作
要使具有执行触发语句特权的任何人都能够执行某个触发器,您可以要求 DBA
创建具有 DBA 特权的 UDR 并为您授予具有 WITH GRANT OPTION 权限的
Execute 特权。
然后您将具有 DBA 特权的 UDR 用作触发操作。任何人都可以执行该触发操
作,因为具有 DBA 特权的 UDR 具有 WITH GRANT OPTION 权限。当您激活
UDR 时,数据库服务器为 DBA 应用特权检查规则。
级联触发器
数据库服务器允许除 Select 触发器外的其它触发器级联,也就是说,一个触发器
的触发器操作可以激活另一个触发器。(有关级联 Select 触发器的限制的更多信
息,请参阅 Select 触发器被激活时的情况。)
级联序列中触发器的最大数目是 61:即初始触发器加上最多 60 个级联触发器。
当序列中的级联触发器数目超过最大值时,数据库服务器返回错误号码 -748,带
有一些信息:

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 483
Exceeded limit on maximum number of cascaded triggers.
下一个示例说明在 stores_demo 数据库中的 manufact 、stock 和 items 表上
实施引用完整性的级联触发器序列。当从 manufact 表删除制造商是,第一个触
发器 del_manu 从 stock 表中删除该制造商的所有条目。stock 表中的每个
DELETE 激活第二个触发器 del_items,该触发器从 items 表删除该制造商的
所有 items。最终,items 表中的每个 DELETE 触发 SPL 例程 log_order,同
时在不能再被填充的 orders 表中创建所有订单的记录。
CREATE TRIGGER del_manu
DELETE ON manufact REFERENCING OLD AS pre_del
FOR EACH ROW(DELETE FROM stock WHERE manu_code =
pre_del.manu_code);
CREATE TRIGGER del_stock
DELETE ON stock REFERENCING OLD AS pre_del
FOR EACH ROW(DELETE FROM items WHERE manu_code =
pre_del.manu_code);
CREATE TRIGGER del_items
DELETE ON items REFERENCING OLD AS pre_del
FOR EACH ROW(EXECUTE PROCEDURE
log_order(pre_del.order_num));
当您不使用日志记录时,manufact 和 stock 表上的引用完整性约束都阻止该示
例中的触发器执行。但是,当您使用日志记录时,触发器成功执行,因为约束检
查被延迟,直至所有的触发操作(包括级联触发器的操作)都完成。关于执行触
发器时如何处理约束的信息,请参阅约束检查。
除了不修改触发 UPDATE 语句别更新的任何列的 UPDATE 语句或 INSERT 语
句外,数据库服务器通过不允许您修改任何级联触发器操作中的触发表俩防止触
发器循环。INSERT 触发器可以在同一个表上定义 UPDATE 触发操作。
约束检查
当您使用日志记录时,数据库服务器延迟触发语句上的约束检查,直至触发操作
列表中的语句执行之后。这等同于执行触发语句前执行 SET CONSTRAINTS ALL
DEFERRED 语句。完成触发操作后,数据库服务器有效执行 SET
CONSTRAINTS constraint IMMEDIATE 语句以检查延迟的约束。该操作允许您

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 484
写入触发器以便是触发器操作能够解析触发语句创建的任何违例。有关更多信
息,请参阅 SET Database Object Mode 语句。
考虑以下示例,表 child 具有约束 r1,该约束引用表 parent。您定义触发器
trig1 并使用 INSERT 语句激活它。在触发操作中,trig1 检查 parent 是否具
有 child 中当前 cola 具有的值的行;如果没有,将插入该行。
CREATE TABLE parent (cola INT PRIMARY KEY);
CREATE TABLE child (cola INT REFERENCES parent CONSTRAINT r1);
CREATE TRIGGER trig1 INSERT ON child
REFERENCING NEW AS new
FOR EACH ROW
WHEN((SELECT COUNT (*) FROM parent
WHERE cola = new.cola) = 0)
-- parent row does not exist
(INSERT INTO parent VALUES (new.cola));
当您将一行插入到引用约束中的子表中时,该行可能在父表中不存在。数据库服
务器不立即在触发语句上返回此错误。相反,它允许触发操作通过将相应的行插
入父表来解析约束违例。如先前示例所示,您可以在触发操作内检查父行是否存
在,如果存在,则可以提供逻辑以绕过 INSERT 操作。
对于没有日志记录的数据库,数据库服务器不延迟触发语句上的约束检查。在此
情况中,如果触发语句违反约束,则数据库服务器立即返回错误。
您不能在触发操作中使用 SET Transaction Mode 语句。当您激活触发器时,数据
库服务器检查此约束,因为该语句可能在 UDR 中发生。
防止触发器相互覆盖
当您使用 UPDATE 语句激活多个触发器时,触发器可能覆盖较早触发器所做的
更改。如果您不希望触发操作相互作用,则可以将该 UPDATE 语句分为多个
UPDATE 语句,每个语句更新单个列。
另一个办法是,您可以为需要触发操作的所有列创建单个更新触发器。然后,在
触发操作内,您可以测试正被更新的列并以希望的顺序应用操作。但是,这种方
法与让数据库服务器应用单个触发器的操作不同,并且有以下缺点:

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 485

如果触发 UPDATE 语句将列设置为当前值,则您无法检测 UPDATE ,
因此触发操作被跳过。您可能希望执行触发操作,即使列值尚未被更改。

如果触发器具有 BEFORE 操作,则它应用于所有列,因为您尚无法检测
某列是否被更改。
远程数据库中的表
您无法在驻留于当前数据库之外的表或视图上创建触发器。但是,您可以在本地
表上定义触发器,该表的触发操作操纵了本地服务器实例的另一个数据库中的
表,或另一个服务器实例的数据库中的表。
以下示例在本地 GBase 8s 服务器实例 dbserver1 (它的会话是已连接的)的当
前数据库中的 newtab 表上定义了 Update 触发器。此处触发操作在远程
dbserver2 GBase 8s 服务器实例的数据库中的 items 表上指定了 UPDATE 操
作:
CREATE TRIGGER upd_nt UPDATE ON newtab
REFERENCING NEW AS post
FOR EACH ROW(UPDATE stores_demo@dbserver2:items
SET quantity = post.qty WHERE stock_num = post.stock
AND manu_code = post.mc);
总之,存在于本地数据库中的触发器支持本地、跨数据库和跨服务器的触发操
作:

在本地数据库中表上的本地触发操作

在本地服务器实例的另一个数据库的表上跨数据库触发操作

在远程服务器实例的数据库的表上的跨服务器触发操作。
定义在远程服务器实例的数据库上的触发器的跨服务器触发操作可以是激活本地
数据库中的一个或多个触发器的事件,本地触发器的触发操作不能是跨服务器操
作。如果来自远程数据库服务器的 SELECT 、DELETE 、INSERT 、MERGE
或 UPDATE 语句是激活本地触发器(其操作指定了远程数据库实例的数据库的
表)的事件,则触发操作失败。
例如,以下触发操作的组合和触发语句在触发语句执行时产生错误:
-- Trigger action from dbserver1 to dbserver3:
CREATE TRIGGER upd_nt UPDATE ON newtab

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 486
REFERENCING NEW AS post
FOR EACH ROW(UPDATE stores_demo@dbserver3:items
SET quantity = post.qty WHERE stock_num = post.stock
AND manu_code = post.mc);

-- Triggering statement from dbserver2:
UPDATE stores_demo@dbserver1:newtab
SET qty = qty * 2 WHERE s_num = 5
AND mc = 'ANZ';
以上的 UPDATE 语句在运行时不会返回错误,因为跨服务器的触发事件不会触
发另一个跨服务器操作。
重要: 作为安全预防措施,用户仅保留角色的自由访问权,不能通过视图或触发
器通过对单独去数据库外表的访问。跨数据库触发操作和跨除雾器触发操作需要
非本地数据库和直接授权给用户或者授权到 PUBLIC 组的表的存取权限。
日志记录和恢复
您可以为数据库创建触发器,使其带有或不带有日志记录。如果具有事务日志记
录的数据库中的触发器失败,则触发语句和触发操作会回滚,就好像这些操作时
触发语句的扩展那样,但是其它事务不回滚。
但是,在不具有事务日志记录的数据库中,当触发语句失败时,您不能回滚。在
此情况中,您负责维护数据库中的数据完整性。触发语句的 UPDATE 、INSERT
或 DELETE 操作在 FOR EACH ROW 部分中的触发操作前发生。如果没有日志
记录的数据库中的触发操作失败,则应用程序必须将触发语句更改的行恢复到先
前值。
如果触发操作调用 UDR,但是 UDR 在异常处理部分终止,则该部分中修改数据的
任何操作都随触发语句回滚。在以下部分示例中,当异常处理程序陷入错误时,
它在表 logtab 中插入一行:
ON EXCEPTION IN (-201)
INSERT INTO logtab values (errno, errstr);
RAISE EXCEPTION -201
END EXCEPTION;

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 487
但是,当 RAISE EXCEPTION 语句返回错误时,数据库服务器回滚该
INSERT ,因为它是触发操作的一部分。如果 UDR 在触发操作外执行,则
INSERT 不回滚。
实现触发操作的 UDR 不能包含任何 BEGIN WORK 、COMMIT WORK 或
ROLLBACK WORK 语句。如果数据库具有事务日志记录,则您必须在触发语句
前开始显式事务,或者该语句本身必须是显式事务。无论哪种情况,UDR 中任何
其它与事务相关的语句都无效。
您可以使用触发器实施数据库服务器当前不支持的引用操作。在没有日志记录的
数据库中,当触发语句失败时,您负责维护数据完整性。
视图上的 INSTEAD OF 触发器
使用 INSTEAD OF 触发器在视图上执行指定的触发操作,而不是执行触发
INSERT 、DELETE 、MERGE 或 UPDATE 语句。
语法

视图上的触发器


GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 488
元素
描述
限制
语法
correlation
触发操作中限定的旧或新列值
的名称
( correlation.column)
在此语句中必须唯一 标识符
trigger
在此为触发器声明的名称
必须在数据库中的触
发器名称中是唯一的
标识符
view
触发视图的名称或同义词。可
以包含 owner. qualifier 。
视图或同义词必须存
在于当前数据库中
标识符
您可以使用触发操作更新视图下的表,在某些情况下更新一般“不可更新”的视
图。当 INSERT 、DELETE 或 UPDATE 语句引用数据库中的特定列时,您还可
以使用 INSTEAD OF 触发器替换其它操作。
在 INSTEAD OF UPDATE 触发器的可选的 REFERENCING 子句中,新相关性
名称可以出现在旧相关性名称之前或之后。
在 GBase 8s 中,CREATE FUNCTION 和 CREATE PROCEDURE 的语句中支持
同一 REFERENCING OLD 和 REFERENCING NEW 语法,以在触发例程中定义
相关性名称。可以在 REATE FUNCTION 或 CREATE PROCEDURE 语句(定义
触发器例程)的 FOR 子句中指定的视图上的 INSTEAD OF 触发器的 Action 子
句中调用触发器例程。
指定的视图有时称为触发视图。此图表的左侧部分(包含视图 规范)定义触发事
件。该图表的剩余部分定义相关性名称和触发操作。
示例
假设 dept 和 emp 是列出部门和员工的表:
CREATE TABLE dept (
deptno INTEGER PRIMARY KEY,
deptname CHAR(20),
manager_num INT
);
CREATE TABLE emp (
empno INTEGER PRIMARY KEY,
empname CHAR(20),

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 489
deptno INTEGER REFERENCES dept(deptno),
startdate DATE
);
ALTER TABLE dept ADD CONSTRAINT(FOREIGN KEY (manager_num)
REFERENCES emp(empno));
下一语句定义 manager_info,它是 dept 和 emp 表中的列构成的视图,包含每
个部门中所有的经理:
CREATE VIEW manager_info AS
SELECT d.deptno, d.deptname, e.empno, e.empname
FROM emp e, dept d WHERE e.empno = d.manager_num;
以下 CREATE TRIGGER 语句创建 manager_info_insert,它是设计为向
manager_info 视图中的 dept 和 emp 表插入行 INSTEAD OF 触发器:
CREATE TRIGGER manager_info_insert
INSTEAD OF INSERT ON manager_info --defines trigger event
REFERENCING NEW AS n --new manager data
FOR EACH ROW --defines trigger action
EXECUTE PROCEDURE instab(n.deptno, n.empno));

CREATE PROCEDURE instab (dno INT, eno INT)
INSERT INTO dept(deptno, manager_num) VALUES(dno, eno);
INSERT INTO emp (empno, deptno) VALUES (eno, dno);
END PROCEDURE;
表、视图、触发器和 SPL 例程创建完成之后,数据库服务器将以下 INSERT 语
句作为触发事件:
INSERT INTO manager_info(deptno, empno) VALUES (08, 4232);
此触发 INSERT 语句不会执行,但是该事件会导致触发操作被执行,同时调用
instab( ) SPL 例程。SPL 例程中的 INSERT 语句向 manager_info 视图中的
emp 和 dept 基本表同时都插入新值。
INSTEAD OF 触发器的 Action 子句
当遇到指定视图的触发事件时,执行触发操作的 SQL 语句,而不是触发语句。
视图上定义的触发器在操作子句中支持以下语法。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 490
INSTEAD OF 触发操作

这与表上触发器的触发操作的语法不完全相同,如触发操作部分所述。由于不支
持 WHEN (condition) ,因此每当遇到 INSTEAD OF 触发事件时都执行同一个触
发操作,且只能指定一个操作列表,而不是为每个 condition 指定独立的列表。
视图上 INSTEAD OF 触发器的限制
您必须是视图的所有者,或者处于 DBA 状态,以便在视图上创建 INSTEAD OF
触发器。简单视图(仅基于一个表)的所有者具有 Insert 、Update 和 Delete 特
权。关于触发器所有者的特权和其它用户的特权间的关系信息,请参阅执行触发
操作的特权。
如果多个表在视图下面,则仅其所有者能创建触发器,但是该所有者能将视图上
的 DML 特权授权给其他用户。
视图上定义的 INSTEAD OF 触发器不能违反触发器上的限制并且必须遵循以下附
加规则:

仅可在视图上定义 INSTEAD OF 触发器,而非在表上。

视图必须对当前数据库是本地的。

视图不能是可更新的视图 WITH CHECK OPTION。

INSTEAD OF 触发器中没有有效的 SELECT 事件或 WHEN 子句。

INSTEAD OF 触发器中没有有效的 BEFORE 和 AFTER 操作。

在 INSTEAD OF UPDATE 触发器中 OF column 子句都是无效的。

每个 INSTEAD OF 触发器都必须指定 FOR EACH ROW。

通过 INSTEAD OF 触发器调用的触发例程不能引用保存点。

GBase 8s SQL 指南:语法
南大通用数据技术股份有限公司 491
视图可以具有任意数量的 INSTEAD OF 触发器以用于定义每种类型的事件
(INSERT 、DELETE 或 UPDATE)。
如果 SPL 的 ON EXCEPTION 语句是从 INSTEAD OF 触发器的 Action 子句发
出,则它不会生效。
就像表上的触发器,INSTEAD OF 触发器的触发操作向 BIGSERIAL 、SERIAL
或 SERIAL8 列插入序列值,不能更新 SQL 通信区域结构的 sqlca.sqlerrd[1] 字
段。已触发的 INSERT 操作可以成功的递增该列的序列数目,但是
sqlca.sqlerrd[1] 字段的值仍为零,而不会重置为序列值。sqlca.sqlerrd[1] 自动可
以显示您通过更新的视图直接插入的新的序列值,但是该字段不能显示系列列上
的 INSTEAD OF Insert 触发器的操作。
更新视图
只有定义视图的 SELECT 语句的以下所有条件都为真,则 INSERT 、DELETE
或 UPDATE 语句可以直接修改视图:

视图中的所有列都来自单个表。

投影列表中的列都不是聚集值。

SELECT 投影列表中没有 UNIQUE 或 DISTINCT 关键字。

视图定义中没有 GROUP BY 子句和 UNION 运算符。

查询不选择计算值和文字值。
但是,如果触发操作修改基本表,则您可以通过使用 INSTEAD OF 触发器绕过
视图上的这些限制。

集群层执行计划开关.............................. 178


创建用于训练的数据表并插入训练数据。
CREATE TABLE patients( id INTEGER NOT NULL,
second_attack INTEGER,
treatment INTEGER,
trait_anxiety INTEGER);
INSERT INTO patients VALUES
( 1,
1,
1,
70),
( 3,
1,
1,
50),
( 5,
1,
0,
40),
( 7,
1,
0,
75),
( 9,
1,
0,
70),
(11,
0,
1,
65),
(13,
0,
1,
45),
(15,
0,
1,
40),
(17,
0,
0,
55),
(19,
0,
0,
50),
( 2,
1,
1,
80),

GBase 8a MPP Cluster 产品手册
5 数据库管理指南
文档版本953(2022-09-15)
南大通用数据技术股份有限公司
1425
( 4,
1,
0,
60),
( 6,
1,
0,
65),
( 8,
1,
0,
80),
(10,
1,
0,
60),
(12,
0,
1,
50),
(14,
0,
1,
35),
(16,
0,
1,
50),
(18,
0,
0,
45),
(20,
0,
0,
60)

训练一个分类模型。
SELECT mllib.logregr_train(
'test.patients',
'test.patients_logregr',
'second_attack',
'array double[1, treatment, trait_anxiety]',
20,
‘cg’,