在INSERT中复制主键是否在Oracle中复制?

时间:2011-01-04 00:27:41

标签: oracle merge insert upsert

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

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

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

INSERT INTO movie_ratings
VALUES (1, 3, 5)

基本上是这个,主键是前2个值,所以更新会是这样的:

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

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

3 个答案:

答案 0 :(得分:10)

MERGE是标准SQL中的'执行INSERT或UPDATE'语句,因此也可能在Oracle SQL中。

是的,你需要一个'table'来合并,但你几乎可以肯定地创建那个表:

 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);

(语法未经过验证。)

答案 1 :(得分:1)

这样做的典型方法是

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

您无法在同一个表上执行其他操作的表上编写触发器。这导致了Oracle错误(变异表)。

答案 2 :(得分:0)

我是一个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表“加入”自己。如果使用“if exists”示例没有性能影响,我会将其用于可读性。