【问题标题】:UPDATE on INSERT duplicate primary key in Oracle?更新在 Oracle 中插入重复的主键?
【发布时间】:2011-01-04 00:27:40
【问题描述】:

我有一个简单的 INSERT 查询,当主键重复时,我需要使用 UPDATE 代替。在 MySQL 中这似乎更容易,在 Oracle 中似乎我需要使用 MERGE。

我能找到的所有 MERGE 示例都有某种“源”和“目标”表,在我的例子中,源和目标是同一个表。我无法理解这些示例来创建自己的查询。

MERGE 是唯一的方法还是有更好的解决方案?

INSERT INTO movie_ratings
VALUES (1, 3, 5)

基本上就是这样,主键是前两个值,所以更新应该是这样的:

UPDATE movie_ratings
SET rating = 8
WHERE mid = 1 AND aid = 3

我想使用一个触发器,它会在调用 INSERT 时自动执行 UPDATE 语句,但前提是主键是重复的。这样做有什么问题吗?我需要一些关于触发器的帮助,因为我在尝试理解它们并自己做时遇到了一些困难。

【问题讨论】:

  • 在这样的示例中,使用 INSERT 中的(可选)列名列表来为我们提供足够的表结构是明智的。也许如果你展示了 MySQL 的功能,人们可能会看到你在追求什么——或者这可能是我的好奇心/懒惰。
  • 表结构是隐式的,是mid(int),aid(int), rating(int)。

标签: oracle merge insert upsert


【解决方案1】:

MERGE 是标准 SQL 中的“根据需要执行 INSERT 或 UPDATE”语句,因此在 Oracle SQL 中也可能如此。

是的,您需要一个“表”来合并,但您几乎可以肯定地动态创建该表:

 MERGE INTO Movie_Ratings M
       USING (SELECT 1 AS mid, 3 AS aid, 8 AS rating FROM dual) N
          ON (M.mid = N.mid AND M.aid = N.aid)
       WHEN     MATCHED THEN UPDATE SET M.rating = N.rating
       WHEN NOT MATCHED THEN INSERT(  mid,   aid,   rating)
                             VALUES(N.mid, N.aid, N.rating);

(语法未验证。)

【讨论】:

  • @jonathan-leffler 我编辑了答案以从“USING ... AS N”中删除“AS”,因为它在 Oracle 11.1 上对我造成了错误
  • Oracle 允许 multi-table 使用 INSERT/UPDATE 语句插入/更新,但不允许使用 MERGE 语句。谈论未完成的软件...
  • 这对我在 Oracle 11g 上不起作用...还有其他人有问题吗?只要我在“on”子句中有多个条件,我就会得到错误:“无法更新 ON 子句中引用的列”。我尝试使用/不使用主键等...
【解决方案2】:

这样做的典型方法是

  • 执行 INSERT 并捕获 DUP_VAL_ON_INDEX,然后改为执行 UPDATE
  • 首先执行 UPDATE,如果 SQL%Rows = 0 则执行 INSERT

您不能在对同一个表执行另一个操作的表上编写触发器。这会导致 Oracle 错误(变异表)。

【讨论】:

  • 不知道,感谢您的澄清。但这应该是一个评论,因为它不一定回答我的问题。
  • @Nazgulled:添加了一些关于 MERGE 的想法(我认为它现在可以作为答案)
  • @Nazgulled:我删除了我的 MERGE-stuff,因为 Jonathan Leffler 的建议实际上可能会这样工作。我想到了一个不同的解决方案。
【解决方案3】:

我是 T-SQL 专家,但在这种情况下触发器不是一个好的解决方案。大多数触发器都不是好的解决方案。在 T-SQL 中,我会简单地执行 IF EXISTS (SELECT * FROM dbo.Table WHERE ...) 但在 Oracle 中,您必须选择计数...

DECLARE 
  cnt NUMBER;
BEGIN
  SELECT COUNT(*)
   INTO cnt
    FROM mytable
  WHERE id = 12345;

  IF( cnt = 0 )
  THEN
    ...
  ELSE
    ...
  END IF;
END;

在这种情况下,您似乎需要 MERGE:

MERGE INTO movie_ratings mr
USING (
  SELECT rating, mid, aid
  WHERE mid = 1 AND aid = 3) mri
ON (mr.movie_ratings_id = mri.movie_ratings_id)

WHEN MATCHED THEN
  UPDATE SET mr.rating = 8 WHERE mr.mid = 1 AND mr.aid = 3

WHEN NOT MATCHED THEN
  INSERT (mr.rating, mr.mid, mr.aid)
  VALUES (1, 3, 8) 

就像我说的,我是一个 T-SQL 人,但这里的基本想法是“加入”movie_rating 表对自己。如果使用“如果存在”示例对性能没有影响,我会使用它来提高可读性。

【讨论】:

    猜你喜欢
    • 2013-08-02
    • 1970-01-01
    • 2012-04-21
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    • 2013-04-28
    • 1970-01-01
    • 2011-02-12
    相关资源
    最近更新 更多