я использую следующее обновление или вставить заявление Oracle на данный момент:Oracle - UPSERT с обновлением не выполняется для немодифицированных значений
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 заявления, но он не работает для обновлений, когда значение не изменяется (обновление не меняет ничего и вставка выполнена, но нарушение ПК происходит).
Полный сливаться в образце:
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 THEN INSERT ... внутренне для сливаться в статье? Второй оператор MERGE INTO терпит неудачу, поскольку обновление ничего не обновляет и поэтому выполняется INSERT, что приводит к нарушению PK, потому что строка уже существует, только значения не изменялись.
после замены 'DSMS' на' TestMerge' в вашем примере, оба оператора отлично работали для меня. – Quassnoi
@Quassnoi: Я нашел некоторую информацию об ошибках в реализациях Oracle MERGE INTO в некоторых версиях Oracle DB, поэтому я думаю, что я могу столкнуться с некоторой ошибкой, потому что я действительно получаю PK-нарушение при выполнении команды слияния во второй раз. В какой версии OraDB вы успешно запускали образец? Я на 10.2.0.1.0 ... – Buthrakaur
Я запускаю версию '10.2.0.1.0' тоже. Созданная вами таблица образцов называется «TestMerge», но в настройках «MERGE» вы используете таблицу «DSMS»: «MERGE INTO DSMS D ...». – Quassnoi