对目标表的限制
目标表对象必须在当前会话连接到的同一 GBase 8s 实例的数据库中。它可为 STANDARD、RAW 或 TEMP 表,或可更新的视图的名称或同义词。如果目标在表层级内为可更新的,则 Delete 子句还删除该目标表的所有子表中相应的行。
发出 MERGE 语句的用户必须持有对目标对象的数据库的 Connect 访问权限(或更高的权限),且必须持有对目标对象的 Insert 权限和 Update 或 Delete 权限,如果 MERGE 语句包括相应的 Insert、Update 或 Delete 子句的话。
下列限制适用于 MERGE 语句的目标表。如果那个表有任何下列的属性,则 MERGE 操作返回错误。
- 目标不可为该源表所在同一表层级中的类型化表。
- 目标不可为“虚拟表接口”(VTI)表。
- 目标不可为 CREATE EXTERNAL TABLE 语句定义的对象。
- 目标不可在远程 GBase 8s 实例的数据库中。
- 目标不可为系统目录表。
- 目标不可为在其上定义启用的 INSTEAD OF 触发器的视图。
- 目标不可为只读视图。
- 目标不可为伪表(在系统数据库中的常驻内存的对象,比如 sysmaster 或 sysadmin 数据库)。
- 目标不可为同一 MERGE 语句的任何子查询的数据源,包括 ON 子句中的、SET 子句中的或 VALUES 子句中的子查询。
- 如果 MERGE 语句包括 DELETE 子句,则目标不可与源表有父表关系,如果通过指定 ON DELETE CASCADE 关键字的启用的引用约束定义此关系的话。
对综合的行长度的限制
MERGE 语句中的源表和目标表不可有合计综合的行长度(= 源表的行大小 + 目标表的行大小)大于 32,767 字节。否则,MERGE 语句失败并报错,如下例所示:
CREATE TABLE t1
(f1 INT,
f2 VARCHAR(10),
lv1 LVARCHAR(5000),
lv2 LVARCHAR(4000),
lv3 LVARCHAR(8000));
CREATE TABLE t2
(f1 INT,
f2 VARCHAR(10),
lv1 LVARCHAR(5000),
lv2 LVARCHAR(4000),
lv3 LVARCHAR(8000));
INSERT INTO t1 (f1,f2) VALUES (1,'t1 1');
INSERT INTO t1 (f1,f2) VALUES (2,'t1 2');
INSERT INTO t1 (f1,f2) VALUES (3,'t1 3');
INSERT INTO t1 (f1,f2,lv1) VALUES (7,'t1 7',
'loooooooooooooooooong');
INSERT INTO t2 (f1,f2) VALUES (3,'t2 3');
INSERT INTO t2 (f1,f2) VALUES (4,'t2 4');
INSERT INTO t2 (f1,f2) VALUES (5,'t2 5');
INSERT INTO t2 (f1,f2) VALUES (6,'t2 6');
MERGE INTO t2 AS o USING t1 AS n ON o.f1 = n.f1
WHEN NOT MATCHED THEN INSERT ( o.f1,o.f2)
VALUES ( n.f1,n.f2);
上述 MERGE 语句失败,因为源和目标表的行长度的总和超出 32,767 字节的上限。
对于仅包括 INSERT 子句(而既没有 DELETE 子句也没有 UPDATE 子句)的 MERGE 操作,您可以通过用 INSERT INTO . . . SELECT 语句代替 MERGE 语句来绕过此行长度限制。对于上述 MERGE 示例中相同的表和数据值,下列 INSERT 语句运行成功:
INSERT INTO t2(f1, f2)
SELECT t1.f1, t1.f2 FROM t1
WHERE NOT EXISTS
(SELECT f1, f2 FROM t2
WHERE t2.f1 = t1.f1);
INSERT INTO t2(f1,f2)
SELECT t1.f1, t1.f2 FROM t1
LEFT JOIN t2 ON t1.f1 = t2.f1
WHERE t2.f1 IS NULL;
在两个 INSERT INTO . . . SELECT 操作之后,表 t2 包含前一个 MERGE 示例受限无法返回的行大小。
对分布式 MERGE 语句的限制
如果源表与目标表不在同一数据库中,则两个数据库都必须满足对跨数据库和跨服务器 DML 操作的兼容性要求:
- 如果一个数据库符合 ANSI,则其他数据库必须也符合 ANSI。
- 如果一个数据库不符合 ANSI 但是用显式的事务日志记录,则其他数据库必须也支持显式的事务日志记录。
- 如果一个数据库不支持事务日志记录,则其他数据库也必须不支持。
- 两个数据库必须有相同的 NLSCASE 敏感性设置。
例如,分布式 MERGE 语句不可在区分大小的数据库中指定源表,而在创建为 NLSCASE INSENSITIVE 的数据库中指定目标表,不论表是否包括 NCHAR 或 NVARCHAR 列。
处理重复的行
在执行 MERGE 时,目标表中的同一行不可被更新或被删除一次以上。在执行了 MERGE 语句之前,请勿尝试更新或删除尚未存在的目标中的任何行。即,没有同一 MERGE 语句插入到目标内的行的更新或删除。
下列 MERGE 语句的示例使用事务表 new_sale 作为源表,从其来在事实表中插入或更新行。在此样例中的结合条件测试 new_sale.cust_id 列值与 sale.cust_id 列值是否相匹配。
MERGE INTO sale USING new_sale AS n
ON sale.cust_id = n.cust_id
WHEN MATCHED THEN UPDATE
SET sale.salecount = sale.salecount + n.salecount
WHEN NOT MATCHED THEN INSERT (cust_id, salecount)
VALUES (n.cust_id, n.salecount);
要执行此 MERGE 语句,数据库服务器结合目标表和源表,并应用指定的相等条件来处理结合的结果:
- 对于满足条件的行(因为 sale.cust_id 值与 new_sale.cust_id 值相匹配),MERGE 根据 SET 子句的指定,更新 sale.salecount 列值。
- 对于不满足条件的行(因为在 sale 表中没有行有与 new_sale.cust_id 相同的 cust_id 值),MERGE 根据 VALUES 子句的指定,将包含 new_sale.cust_id 和 new_sale.salecount 值的新行插入 sale 表内。
对于先前示例中的 MERGE 语句,假设 sale 目标包含两条记录,而 new_sale 源表包含三条记录。
表 1. “sale”表中的记录 | |
cust_id | sale_count |
Tom | 129 |
Julie | 230 |
表 2. “new_sale”表中的记录 | |
cust_id | sale_count |
Tom | 20 |
Julie | 3 |
Julie | 10 |
当通过指定表达式 sale.cust_id = new_sale.cust_id 作为匹配条件将 new_sale 合并至 sale 内时,MERGE 语句返回错误,因为它尝试超过一次更新 sale 目标表中的记录之一。