Oracle 之 merge 误区讨论

merge 五大误区

  1. 不能更新 ON 子句引用的列

MERGE INTO T2

USING T1

ON (T1.NAME=T2.NAME)

WHEN MATCHED THEN

UPDATE

SET T2.NAME=T1.NAME;

ORA-38104: 无法更新 ON 子句中引用的列: “T2”.“NAME”

  1. DELETE 子句的 WHERE 顺序必须最后

MERGE INTO T2

USING T1

ON (T1.NAME=T2.NAME)

WHEN MATCHED THEN

UPDATE

SET T2.MONEY=T1.MONEY+T2.MONEY

DELETE WHERE (T2.NAME = ‘A’)

WHERE T1.NAME=‘A’;

ORA-00933: SQL 命令未正确结束

–改为如下即可:

MERGE INTO T2

USING T1

ON (T1.NAME=T2.NAME)

WHEN MATCHED THEN

UPDATE

SET T2.MONEY=T1.MONEY+T2.MONEY

WHERE T1.NAME=‘A’

DELETE WHERE (T2.NAME = ‘A’);

3.DELETE 子句只可以删除目标表,而无法删除源表, 无论是否在 where 后面加原表限制条件,都无法删除原表的数据

/*

 这里需要引起注意,无论 DELETE WHERE (T2.NAME = ‘A’) 这个写法的 T2 是否改写为 T1,效果都一样,都是对目标表进行删除!

*/

4. 更新同一张表的数据, 需担心 USING 的空值

/*

需求为对 T2 表进行自我更新,如果在 T2 表中发现 NAME=D 的记录,就将该记录的 MONEY 字段更新为 100,如果 NAME=D 的记录不存在,

则自动增加,NAME=D 并且 MONEY=100 的记录。根据语法完成如下代码:

*/

MERGE INTO T2

USING (select * from t2 where NAME=‘D’) T

ON (T.NAME=T2.NAME)

WHEN MATCHED THEN

UPDATE

SET T2.MONEY=100

WHEN NOT MATCHED THEN

INSERT

VALUES (‘D’,200);

–但是查询发现,本来 T 表应该因为 NAME=D 不存在而要增加记录,但是实际却根本无变化。

/*

   原来是因为此时 select * from t2 where NAME=’D’为 NULL, 所以出现了无法插入的情况,

   我们可以利用 COUNT(*) 的值不会为空的特点来等价改造,具体如下:

*/

MERGE INTO T2

USING (select COUNT(*) CNT from t2 where NAME=‘D’) T

ON (T.CNT<>0)

WHEN MATCHED THEN

UPDATE

SET T2.MONEY=100

WHEN NOT MATCHED THEN

INSERT

VALUES (‘D’,100);

  1. 必须要在源表中获得一组稳定的行

—构造数据,请注意这里多插入一条 A 记录,就产生了 ORA-30926 错误

INSERT INTO T1 VALUES (‘A’,30);

COMMIT;

—此时继续执行如下

MERGE INTO T2

USING T1

ON (T1.NAME=T2.NAME)

WHEN MATCHED THEN

UPDATE

SET T2.MONEY=T1.MONEY+T2.MONEY;

ORA-30926: 无法在源表中获得一组稳定的行

/*

oracle 中的 merge 语句应该保证 on 中的条件的唯一性,T1.NAME=T2.NAME 的时候,T1 表记录对应到了 T2 表的两条记录,所以就出错了。

解决方法很简单,比如我们可以对 T1 表和 T2 表的关联字段建主还键,这样基本上就不可能出现这样的问题,而且一般而言,MERGE 语句的关联字段互相有主键,

MERGE 的效率将比较高!或者是将 T1 表的 ID 列做一个聚合,这样归并成单条,也能避免此类错误。如:

*/   

MERGE INTO T2

  USING (select NAME,SUM(MONEY) AS MONEY FROM T1 GROUP BY NAME)T1

  ON (T1.NAME=T2.NAME)

  WHEN MATCHED THEN

  UPDATE

  SET T2.MONEY=T1.MONEY+T2.MONEY;

–正常情况下,一般出现重复的 NAME 需要引起怀疑,不太应该。