Я использую следующее обновление или вставьте оператор 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 выполняет фиктивное обновление, если данные совпадают с предоставленными значениями параметров. Я не возражаю против фиктивного обновления в нормальной ситуации, но есть система репликации / синхронизации, построенная на этой таблице с использованием триггеров для таблиц для захвата обновленных записей, и выполнение этого оператора часто для многих записей просто означает, что я вызову огромный трафик в триггерах и система синхронизации.
Есть ли какой-нибудь простой способ переформулировать этот код, чтобы оператор update не обновлял запись, если бы в этом не было необходимости, без использования следующего контрольного кода IF-EXISTS, который, на мой взгляд, недостаточно изящен и, возможно, также не самый эффективный для этой задачи? 1006 *
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? Второй оператор MERGE INTO завершается неудачно, потому что обновление ничего не обновляет, поэтому выполняется INSERT, что приводит к нарушению PK, поскольку строка уже существует, а значения не изменились.