通常情况下,我们需要使用两个不同的查询执行更新或插入到同一个表中。我想看看这是否可以使用合并语句在表上完成。
我只想知道这是否可以完成。否则,我将不得不坚持将查询分别分离回更新/插入操作。
这是我到目前为止所拥有的:
方法一:
MERGE INTO TABLEA TARGET
USING (
SELECT 1 FROM DUAL
) SOURCE
ON (TARGET.TARGET.COLA = '001'
AND TARGET.TARGET.COLB = '1111111'
AND TARGET.COLC = '201302'
)
WHEN MATCHED THEN
UPDATE SET TARGET.COLA = '001'
,TARGET.COLB = '1111111'
,TARGET.COLC = '201304'
,TARGET.CREATEDATE = SYSDATE
,TARGET.USERID = 'USERA'
WHEN NOT MATCHED THEN
INSERT (TARGET.COLA
,TARGET.COLB
,TARGET.COLC
,TARGET.COLD
,TARGET.CREATEDATE
,TARGET.USERID)
VALUES('001'
,'1111111'
,'201304'
,'123'
,SYSDATE
,'USERA')
起初这种方法对我来说很有意义,因为我总是会从源返回结果,并且我会相应地更新和插入。但是,oracle 拒绝遵循这一点:
SQL 错误:ORA-38104:无法更新 ON 子句中引用的列:“TARGET”。“EFF_FISCAL_YR_PD_NBR”38104。00000 -“无法更新 ON 子句中引用的列:%s” *原因:UPDATE SET 的 LHS 包含ON 子句中引用的列
方法二:
MERGE INTO TABLEA TARGET
USING (
SELECT ROWID AS RID,COLA,COLB,COLC
FROM TABLEA
WHERE COLA = '001'
AND COLB = '1111111'
AND COLC = '201301'
) SOURCE
ON (TARGET.ROWID = SOURCE.RID)
WHEN MATCHED THEN
UPDATE SET TARGET.COLA = '001'
,TARGET.COLB = '1111111'
,TARGET.COLC = '201304'
,TARGET.CREATEDATE = SYSDATE
,TARGET.USERID = 'USERA'
WHEN NOT MATCHED THEN
INSERT (TARGET.COLA
,TARGET.COLB
,TARGET.COLC
,TARGET.COLD
,TARGET.CREATEDATE
,TARGET.USERID)
VALUES('001'
,'1111111'
,'201304'
,'123'
,SYSDATE
,'USERA')
这背后的逻辑是,如果我尝试从源表中查找值,并且它匹配,它将找到记录并使用这些值更新自己。但是,如果不匹配,则尝试插入时会出现问题。因为源被过滤了,所以没有记录被返回,因此目标没有什么可以匹配的,也没有任何内容被插入。如果在 SOURCE 中找不到任何记录(隐式与目标不匹配),我想做的是插入,特别是因为插入语句不包含从变量而不是源本身传入的值。
我尝试将源更新为如下所示:
SELECT ROWID AS RID,COLA,COLB,COLC
FROM TABLEA
WHERE COLA = '001'
AND COLB = '1111111'
AND COLC = '201301'
UNION ALL
SELECT ROWID,NULL,NULL,NULL FROM DUAL
但是这样做的问题是,合并会更新它匹配的记录,并插入它不匹配的记录。
对于那些想知道我为什么使用 ROWID 的人。这是因为设计(不是我设计的)表明 COLA 和 COLB 将是组合的主键,将用作表上的索引。不允许 COLA、COLB 和 COLC 重复,但它们都可以通过前端界面更新。我了解 ROWID 的缺陷,但是因为我只使用一个表作为目标和源,无论我在表上执行任何 CRUD 操作,ROWID 将始终与自身匹配。
摘要:我只有在对匹配项执行更新时才使自我合并起作用,但插入不起作用。