現在、次の update または insert 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;
これは、データが指定されたパラメーター値と同じである場合に更新ステートメントがダミーの更新を実行することを除いて、正常に実行されます。通常の状況ではダミーの更新は気にしませんが、テーブルのトリガーを使用して更新されたレコードをキャプチャし、このステートメントを多くのレコードに対して頻繁に実行することは、単にトリガーと同期システム。
次の IF-EXISTS チェック コードを使用せずに更新ステートメントがレコードを更新しないように、このコードを再定式化する簡単な方法はありますか?
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...IF SQL%ROWCOUNT=0 THEN INSERT... を MERGE INTO 句に内部的に使用しているように見えますか? 2 番目の MERGE INTO ステートメントは失敗します。update は何も更新せず、INSERT が実行され、値が変更されなかっただけで行が既に存在するため、PK 違反が発生するためです。