#sql #oracle
#sql #Oracle
Вопрос:
Я пытаюсь запустить набор SQL, который проверит, существует ли в таблице составное значение первичного ключа. если она существует, то обновите таблицу, в противном случае вставьте новые значения. Я думал, что оператор merge — это способ сделать это. Но слияние, которое я написал, приводит к объединению 0 строк, когда я его запускаю. Я ожидал бы, что условие NOT MATCHED возникнет в следующем примере, но это не так. Вот сценарий для его тестирования и СЛИЯНИЯ, которое я пытаюсь:
CREATE TABLE curformat (storeent_id INTEGER,
setccurr VARCHAR2(3),
roundingmultiple INTEGER,
numbrusg_id INTEGER,
roundingmethod VARCHAR2(1),
decimalplaces INTEGER,
MINAPPROVEAMOUNT NUMBER,
optcounter INTEGER);
INSERT INTO curformat VALUES(-1, 'USD', 1, -1, 'R', 2, NULL, NULL);
----------------------------------------------------------------------
MERGE INTO curformat cf
USING (SELECT *
FROM curformat
WHERE storeent_id = 10201
AND setccurr = 'USD'
AND numbrusg_id = -1
) current_curformat
ON (cf.storeent_id = current_curformat.storeent_id
AND cf.setccurr = current_curformat.setccurr
AND cf.numbrusg_id = current_curformat.numbrusg_id
)
WHEN MATCHED THEN UPDATE
SET roundingmultiple = 1,
roundingmethod = 'R',
decimalplaces = 2,
minapproveamount = NULL
WHEN NOT MATCHED THEN INSERT (storeent_id, setccurr, roundingmultiple, numbrusg_id, roundingmethod, decimalplaces, minapproveamount)
VALUES (10201, 'USD', 1, -1, 'R', 2, NULL
);
В этом случае, поскольку комбинация
WHERE storeent_id = 10201
AND setccurr = 'USD'
AND numbrusg_id = -1
неверно, я бы подумал, что КОГДА НЕ БУДЕТ ВЫПОЛНЕНО СОВПАДЕНИЕ.
Кто-нибудь может помочь мне понять, чего я здесь не понимаю? Я предполагаю, что я неправильно использую оператор СЛИЯНИЯ?
Ответ №1:
sstan уже объяснил, почему ваша версия MERGE не будет работать. Когда вы хотите обновить / вставить в curformat
, вы не извлекаете строки из этой таблицы. У вас есть «новые» строки, которые вы либо хотите вставить в свою таблицу, либо хотите использовать для обновления.
Итак, на самом деле исправить ваше заявление о слиянии легко. Обратите пристальное внимание на то, что такое «дельта» ( current_format
используется в предложении USING). В данном случае это строка, созданная «из воздуха» (что в Oracle означает «созданная из dual
таблицы»).
MERGE INTO curformat cf
USING (SELECT 10201 as storeent_id,
'USD' as setccurr,
-1 as numbrusg_id
FROM dual
) current_curformat
ON (cf.storeent_id = current_curformat.storeent_id
AND cf.setccurr = current_curformat.setccurr
AND cf.numbrusg_id = current_curformat.numbrusg_id
)
WHEN MATCHED THEN UPDATE
SET roundingmultiple = 1,
roundingmethod = 'R',
decimalplaces = 2,
minapproveamount = NULL
WHEN NOT MATCHED THEN INSERT (storeent_id, setccurr, roundingmultiple, numbrusg_id,
roundingmethod, decimalplaces, minapproveamount)
VALUES (10201, 'USD', 1, -1, 'R', 2, NULL
);
Это сделает именно то, что вы хотите.
Однако здесь мы жестко запрограммировали значения, которые будут вставляться, когда совпадений нет. Это очень плохая практика. Правильный способ сделать это (просто показать последние две строки, которые являются единственными измененными):
VALUES (current_format.storeent_id, current_format.setccurr,
1, current_format.numbrusg_id, 'R', 2, NULL
);
Ответ №2:
Похоже, вы смотрите на это в обратном направлении. Если мы возьмем базовый merge
синтаксис:
merge into <target> using <source> ...
… идея заключается в том, что у вас есть набор строк, определенных как the source
, которые могут совпадать или не совпадать с некоторыми строками в вашем target
, и для которых вы определяете логику того, как объединить source
в target
. Но для того, чтобы merge
оператор вообще выполнял какую-либо работу, source
он не может быть пустым.
В вашем случае source
определяется как:
SELECT *
FROM curformat
WHERE storeent_id = 10201
AND setccurr = 'USD'
AND numbrusg_id = -1
… который не возвращает строк, поэтому делать нечего. target
хотя может быть пустым, но если source
пусто, объединять не во target
что.