【发布时间】:2011-04-30 05:38:43
【问题描述】:
嗨,
我有一个表,如果记录已经存在,则必须在其中修改记录,否则必须插入新记录。
Oracle sql 不接受IF EXISTS,否则我会执行if - update - else - insert 查询。我看过MERGE,但它只适用于多个表。我该怎么办?
【问题讨论】:
嗨,
我有一个表,如果记录已经存在,则必须在其中修改记录,否则必须插入新记录。
Oracle sql 不接受IF EXISTS,否则我会执行if - update - else - insert 查询。我看过MERGE,但它只适用于多个表。我该怎么办?
【问题讨论】:
MERGE 不需要“多个表”,但它确实需要一个查询作为源。这样的事情应该可以工作:
MERGE INTO mytable d
USING (SELECT 1 id, 'x' name from dual) s
ON (d.id = s.id)
WHEN MATCHED THEN UPDATE SET d.name = s.name
WHEN NOT MATCHED THEN INSERT (id, name) VALUES (s.id, s.name);
您也可以在 PL/SQL 中执行此操作:
BEGIN
INSERT INTO mytable (id, name) VALUES (1, 'x');
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
UPDATE mytable
SET name = 'x'
WHERE id = 1;
END;
【讨论】:
MERGE 指令,但至于DUP_VAL_ON_INDEX 处理异常,这绝对是一个不错的解决方案,知道Oracle 异常处理经常用于此类行为! =)
MERGE INTO 语句后在 OracleSQL 数据库中查看结果,请确保通过运行 COMMIT; 提交事务
merge into MY_TABLE tgt
using (select [expressions]
from dual ) src
on (src.key_condition = tgt.key_condition)
when matched then
update tgt
set tgt.column1 = src.column1 [,...]
when not matched then
insert into tgt
([list of columns])
values
(src.column1 [,...]);
【讨论】:
您可以使用SQL%ROWCOUNT Oracle 变量:
UPDATE table1
SET field2 = value2,
field3 = value3
WHERE field1 = value1;
IF (SQL%ROWCOUNT = 0) THEN
INSERT INTO table (field1, field2, field3)
VALUES (value1, value2, value3);
END IF;
确定您的主键(即field1)是否有值然后相应地执行插入或更新会更容易。也就是说,如果您将所述值用作存储过程的参数。
【讨论】:
update 触及零行的情况,因此您假设没有行并需要执行insert,但平均而言-time 有人做了insert,所以你的insert 因违反唯一约束而失败。这就是为什么重要的是先执行insert(并捕获违反唯一约束)然后执行update,而不是相反。
我一直这样做的方式(假设数据永远不会被删除,只会插入)是
insert,如果由于违反唯一约束而失败,那么您知道该行存在,update
不幸的是,许多框架(例如 Hibernate)将所有数据库错误(例如违反唯一约束)视为不可恢复的条件,因此并不总是那么容易。 (在 Hibernate 中,解决方案是打开一个新的会话/事务来执行这个insert 命令。)
你不能只做一个select count(*) .. where ..,即使它返回零,因此你选择在你做select和insert之间做一个insert,其他人可能有@ 987654328@ed 行,因此您的 insert 将失败。
【讨论】:
HC 方式 :)
DECLARE
rt_mytable mytable%ROWTYPE;
CURSOR update_mytable_cursor(p_rt_mytable IN mytable%ROWTYPE) IS
SELECT *
FROM mytable
WHERE ID = p_rt_mytable.ID
FOR UPDATE;
BEGIN
rt_mytable.ID := 1;
rt_mytable.NAME := 'x';
INSERT INTO mytable VALUES (rt_mytable);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
<<update_mytable>>
FOR i IN update_mytable_cursor(rt_mytable) LOOP
UPDATE mytable SET
NAME = p_rt_mytable.NAME
WHERE CURRENT OF update_mytable_cursor;
END LOOP update_mytable;
END;
【讨论】:
如果您想在Oracle 中使用UPSERT/MERGE 命令,请参考this 问题。否则,只需在客户端解决您的问题,首先执行count(1),然后再决定是插入还是更新。
【讨论】: