Oracle MERGE: срабатывает только NOT MATCHED

База данных: Oracle

Таблица:

CREATE TABLE TABLE_FOR_TESTS (
    d DATE,
    t NUMBER(8)
)

MERGE:

MERGE INTO TABLE_FOR_TESTS
    USING DUAL
    ON ((SELECT COUNT(*) FROM TABLE_FOR_TESTS) = 1)
    WHEN MATCHED THEN
        UPDATE SET T = T+1
    WHEN NOT MATCHED THEN         
        INSERT (D, T) VALUES (sysdate, 1)

или же

    ...
    ON ((SELECT T FROM TABLE_FOR_TESTS) is not null)
    ...

Я буду ссылаться на первую версию MERGE, но вторая имеет тот же эффект.

1) Я впервые запускаю этот MERGE

  • результат: ожидается (поскольку элемента нет, условие ВКЛ ложно => ВСТАВИТЬ)

2) Здесь я бегу:

SELECT COUNT(*) FROM TABLE_FOR_TESTS

и это вывод "1".

3) Я запускаю этот MERGE во второй раз

  • результат: неожиданный (INSERT), ожидаемый: UPDATE (работает только на sqlfiddle)

Почему условие ON ложно при N-м прогоне (N>1)? (если это было "1" как вывод на 2))

(просто для проверки: если я изменю условие на ON (1=1) до второго запуска работает хорошо: ОБНОВЛЕНИЕ сделано)

1 ответ

Решение

Я думаю, вы неправильно поняли, для чего нужно объединение.

Я ожидаю, что ваш стол будет что-то вроде:

CREATE TABLE TABLE_FOR_TESTS (
    d DATE,
    t NUMBER(8),
    CONSTRAINT TABLE_FOR_TESTS_PK PRIMARY KEY (d)
)

и тогда оператор слияния может быть:

MERGE INTO TABLE_FOR_TESTS t
  USING (SELECT trunc(sysdate) d FROM DUAL) s
    ON (s.d = t.d)
  WHEN MATCHED THEN
    UPDATE SET t = t+1
  WHEN NOT MATCHED THEN         
    INSERT (d, t) VALUES (trunc(sysdate), 1)

где соединение находится на первичном ключе таблицы и либо обновляется, либо вставляется в зависимости от того, существует ли запись для этого значения PK.

Это будет иметь максимум одну запись в день, и t будет содержать количество выполнений этого оператора в день (при условии отсутствия другого DML для TABLE_FOR_TESTS).

Примечание: sysdate сам по себе включает компонент времени. trunc(sysdate) удаляет его и устанавливает время 00:00:00.

Другие вопросы по тегам