我正在使用以下更新或插入Oracle语句:
BEGIN
UPDATE DSMS
SET SURNAME = :SURNAME
WHERE DSM = :DSM;
IF (SQL%ROWCOUNT = 0) THEN
INSERT INTO DSMS
(DSM, SURNAME)
VALUES
(:DSM, :SURNAME);
END IF;
END;
如果数据与提供的参数值相同,则update语句执行虚拟更新,但运行正常。我不介意正常情况下的虚拟更新,但是在这个表上有一个复制/同步系统构建,使用表上的触发器捕获更新的记录并经常为许多记录执行此语句只是意味着我会在触发器和同步系统。
有没有任何简单的方法如何重新编写此代码,如果没有必要,更新语句不会更新记录而不使用以下IF-EXISTS检查代码,我发现这些代码不够流畅,也可能对此任务不是最有效的? / p>
DECLARE
CNT NUMBER;
BEGIN
SELECT COUNT(1) INTO CNT FROM DSMS WHERE DSM = :DSM;
IF SQL%FOUND THEN
UPDATE DSMS
SET SURNAME = :SURNAME
WHERE DSM = :DSM
AND SURNAME != :SURNAME;
ELSE
INSERT INTO DSMS
(DSM, SURNAME)
VALUES
(:DSM, :SURNAME);
END IF;
END;
我也尝试过使用MERGE INTO语句,但是当未修改值时,它不适用于更新(更新不会修改任何内容并执行插入,但会发生PK违规)。
完整MERGE INTO样本:
CREATE TABLE DSMS(
dsm VARCHAR2(10) NOT NULL PRIMARY KEY,
surname VARCHAR2(10) NOT NULL
);
> Table created
-- :DSM = 'xx', :SURNAME = 'xx'
MERGE INTO DSMS D
USING (SELECT :DSM AS DSM,
:SURNAME AS SURNAME
FROM DUAL) V
ON (D.DSM = V.DSM)
WHEN MATCHED THEN
UPDATE
SET SURNAME = V.SURNAME
WHERE D.SURNAME <> V.SURNAME
WHEN NOT MATCHED THEN
INSERT (DSM, SURNAME)
VALUES (V.DSM, V.SURNAME);
> Ok - record inserted
-- :DSM = 'xx', :SURNAME = 'xx'
MERGE INTO DSMS D
USING (SELECT :DSM AS DSM,
:SURNAME AS SURNAME
FROM DUAL) V
ON (D.DSM = V.DSM)
WHEN MATCHED THEN
UPDATE
SET SURNAME = V.SURNAME
WHERE D.SURNAME <> V.SURNAME
WHEN NOT MATCHED THEN
INSERT (DSM, SURNAME)
VALUES (V.DSM, V.SURNAME);
> ORA-00001 - Unique constraint violated (PK violation)
看起来Oracle正在使用UPDATE ...如果SQL%ROWCOUNT = 0那么INSERT INSALL ......内部用于MERGE INTO子句?第二个MERGE INTO语句失败,因为更新不会更新任何内容,因此执行INSERT会导致PK违规,因为行已存在,只是值没有更改。
答案 0 :(得分:4)
MERGE
INTO dsms d
USING (
SELECT :DSM AS dsm, :SURNAME AS surname, :FIRSTNAME AS firstname, :VALID AS valud
FROM dual
) v
ON (d.dsm = q.dsm)
WHEN MATCHED THEN
UPDATE
SET SURNAME = v.SURNAME, FIRSTNAME = v.FIRSTNAME, VALID = v.VALID
WHERE d.surname <> v.surname
OR d.firstname <> v.firstname
OR d.valid <> v.valid
WHEN NOT MATCHED THEN
INSERT
INTO (SURNAME, FIRSTNAME, VALID)
VALUES (SURNAME, FIRSTNAME, VALID)
如果您的字段接受NULL
值,则可能需要添加额外的NULL
支票。
答案 1 :(得分:2)
你可以把它转过来。取决于插入与更新的比例,但是,与大量更新一样,您将运行大量失败的插入。
BEGIN
INSERT INTO DSMS
(DSM, SURNAME)
VALUES
(:DSM, :SURNAME);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
UPDATE DSMS
SET SURNAME = :SURNAME
WHERE DSM = :DSM
AND SURNAME != :SURNAME;
END;