3

現在、次の 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 違反が発生するためです。

4

2 に答える 2

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ます。

于 2010-05-26T09:33:10.503 に答える
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;
于 2010-05-26T23:35:18.390 に答える