Domanda

sto usando seguente aggiornamento o inserimento dichiarazione Oracle in questo momento:

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;

Questo funziona bene, tranne che le esegue un'istruzione UPDATE fittizi aggiornamento se i dati sono uguali ai valori dei parametri forniti. Non mi dispiacerebbe l'aggiornamento fittizio in situazione normale, ma c'è un sistema di compilazione replica / sincronizzazione su questo tavolo utilizzando i trigger sulle tabelle per catturare aggiornato i record e l'esecuzione di questa dichiarazione di frequente per molti record significa semplicemente che avrei causo traffico enorme nei trigger e il sistema di sincronizzazione.

Esiste un metodo semplice come riformulare questo codice che la dichiarazione di aggiornamento non sarebbe aggiornare il record, se non necessario, senza l'utilizzo di seguito IF-ESISTE codice di controllo che trovo abbastanza per non elegante e forse anche non più efficiente per questo compito?

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;

Ho anche provato ad utilizzare dichiarazione si fondono in, ma non funziona per gli aggiornamenti quando il valore non viene modificato (aggiornamento non modifica nulla e viene eseguito inserto, ma si verifica la violazione PK).

Unisci completa di esempio in:

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)

Sembra che Oracle sta usando UPDATE ... se SQL% ROWCOUNT = 0 quindi inserire ... internamente per fondersi in clausola? Il secondo si fondono in istruzione ha esito negativo, perché l'aggiornamento non aggiorna nulla e quindi INSERT viene eseguita che si traduce in violazione PK, perché riga esiste già solo i valori non sono cambiati.

È stato utile?

Soluzione

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)

Potrebbe essere necessario aggiungere controlli NULL in più se i vostri campi accettano valori NULL.

Altri suggerimenti

È possibile attivare sulla sua testa. Dipende dal rapporto di inserti di aggiornamenti anche se, come con un sacco di aggiornamenti vi sarà l'esecuzione di un sacco di inserti che non riescono.

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top