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.