0

通常情况下,我们需要使用两个不同的查询执行更新或插入到同一个表中。我想看看这是否可以使用合并语句在表上完成。

我只想知道这是否可以完成。否则,我将不得不坚持将查询分别分离回更新/插入操作。

这是我到目前为止所拥有的:

方法一:

          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 将始终与自身匹配。

摘要:我只有在对匹配项执行更新时才使自我合并起作用,但插入不起作用。

4

3 回答 3

1

如果我理解正确的话,COLA、COLB 和 COLC 是 TABLEA 的复合主键

如果是这种情况,您实际上不需要在此处使用 ROWID,只需从对偶中进行选择,然后像第一次尝试一样在 ON 语句中使用复合键即可完成您需要的操作。

您不需要更新主键列,因此可以在 ON 子句中使用它们。

      MERGE INTO TABLEA TARGET
      USING (
            SELECT '001' COLA,
                   '1111111' COLB,
                   '201301' COLC
            FROM DUAL
      ) SOURCE
      ON (TARGET.COLA = SOURCE.COLA
          AND TARGET.COLB = SOURCE.COLB
          AND TARGET.COLC = SOURCE.COLC
          )
      WHEN MATCHED THEN
         UPDATE SET 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')
于 2013-11-06T00:18:13.147 回答
1

哇,这花了我很长时间才完成!

我使用方法 3(UNION ALL 与来自 d​​ual 的空记录集)走在正确的轨道上。

你只需要满足三个条件:

  1. 您总是需要从源表返回一个结果集,但以一种与目标不匹配的方式。
  2. 您不能同时返回匹配集和非匹配集,否则您将同时执行插入和更新
  3. 您的主键是可更新的,因为它在多个列上匹配。我对它们有独特的限制,所以如果我尝试复制它会引发错误

所以,源代码应该是这样的:

            SELECT RID,COLA,COLB,COLC FROM
            (
                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
                ORDER BY COLA ASC
            ) f
            WHERE ROWNUM <= 1

所以你返回一个记录。如果满足 where 子句,则按 ASCENDING ORDER 对数据集进行排序,并仅返回顶部记录集。这样,合并将基于此更新。如果 where 子句(不是包含 ROWNUM 的子句)返回零值,它仍将返回空记录集,并且合并将基于此插入。

不止一项记录

如果您真的想变得疯狂并获得多条记录(在我的情况下,我需要 1 条),那么您必须使用聚合(或分析函数)获取匹配记录集的计数并将其填充到变量,以便 where 子句标准如下所示:

WHERE ROWNUM <= COUNTOFRETURNEDRESULTS
于 2013-11-06T14:26:57.093 回答
0

匹配时使用 (从 DUAL 中选择 1) s on (t.COL1 = :p1 ) 合并到 MY_TARGET t 中,然后在不匹配时更新设置 t.COL3 = :p3 然后插入 (COL1, COL2, COL3) 值 (:p1, : p2, :p3)

您必须有一些东西要返回才能插入

于 2014-03-03T15:35:34.463 回答