如果主键不存在,则需要在表中插入行,否则更新现有行

时间:2016-10-15 19:08:11

标签: sql oracle

我正在尝试运行一堆SQL来检查表中是否存在复合主键值。如果存在,则更新表,否则插入新值。我认为合并声明是这样做的方式。但是我编写的合并在运行时会合并0行。我希望在以下示例中出现NOT MATCHED条件,但事实并非如此。这是测试它的脚本和我正在尝试的MERGE:

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

不是真的,我原本以为什么时候不匹配会被运行。 任何人都可以帮助我理解我在这里不理解的东西吗?我想我错误地使用了MERGE语句?

2 个答案:

答案 0 :(得分:3)

sstan已经解释了为什么你的MERGE版本不起作用。当您想要更新/插入curformat时,您不会从该表中提取行。你有"新"您想要插入表中或想要用于更新的行。

所以 - 实际上很容易修复你的MERGE语句。密切关注" delta"虽然(在USING子句中使用current_format)。在这种情况下,它是一个由"稀薄空气" (在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
             );

答案 1 :(得分:1)

看起来你正在向后看。如果我们采用基本的merge语法:

merge into <target> using <source> ...

...我们的想法是,您有一组定义为source的行,这些行可能与target中的某些行匹配,也可能不匹配,并为您定义了如何使用的逻辑将source合并到target。但是,为了使merge语句完全执行任何工作,source不能为空。

在您的情况下,source定义为:

SELECT *
  FROM curformat
 WHERE storeent_id = 10201
   AND setccurr = 'USD'
   AND numbrusg_id = -1

...不返回任何行,因此无需执行任何操作。 target可以为空,但如果source为空,则无法合并到target