SELECT CASE在Oracle中使用NOT EXISTS失败

时间:2016-12-10 16:28:14

标签: oracle plsql rdbms

我一直在尝试找到在Oracle PL SQL中使用If_Exists()样式语句的解决方案。我正在尝试创建一个触发器,当成员试图输入gunsOwned表中拥有的新枪时,检查枪支表中是否存在某个气枪。如果枪支表中不存在枪支,则必须在枪支所有枪输入枪支表之前输入枪支,否则会违反参考完整性,因为枪支中的Make和Model是Make和Model的外键。在枪支表中。但是我一直在使用编译错误创建Trigger,并且我的所有属性名称都是正确的,所以不知道为什么select case语句不起作用。这是代码:

CREATE TRIGGER updateGuns 
BEFORE INSERT ON GunsOwned  
FOR EACH ROW
DECLARE
   MemberAddingGun NUMBER;
   NewMake VARCHAR2(30);
   NewModel VARCHAR2(30);
BEGIN
   MemberAddingGun := :NEW.OwnerID;
   NewMake := :NEW.MakeOwned;
   NewModel := :NEW.ModelOwned;
   SELECT CASE gunExists
    WHEN NOT EXISTS(SELECT Make, Model FROM Guns WHERE Make=NewMake AND Model=NewModel)
   THEN 
    INSERT INTO Guns VALUES(NewMake, NewModel);
   END
   UPDATE Member
   SET NumOfGuns = NumOfGuns+1
   WHERE MemberID = MemberAddingGun;
END updateGuns;
.
RUN;

有人可以帮忙吗?

谢谢!

3 个答案:

答案 0 :(得分:0)

使用简单的INSERT ... SELECT ... WHERE而不是CASEIF语句:

INSERT INTO Guns( colname1, colname2 )
SELECT NewMake, NewModel FROM dual
WHERE NOT EXISTS(
     SELECT null FROM Guns WHERE Make=NewMake AND Model=NewModel
);

BTW - 在多用户环境中检查记录是否存在总是会失败,因为SQL不会显示提交的记录,并且您将在Guns表中获得重复记录。
在这种情况下,您需要某种同步。

答案 1 :(得分:0)

在设置适当的标志后,只需使用IF

DECLARE
   v_flag number;
BEGIN    
   SELECT (CASE WHEN EXISTS (SELECT 1
                             FROM Guns
                             WHERE Make = :New.MakeOwned AND Model = :New.Model AND rownum = 1;
                            )
                THEN 1 ELSE 0
            END)
   INTO v_flag
   FROM DUAL;

   IF v_flag = 0
   THEN 
      INSERT INTO Guns(Make, Model) VALUES (:New.Make, :New.Model);
   END IF;

   UPDATE Member
       SET NumOfGuns = NumOfGuns + 1
       WHERE MemberID = :New.OwnerId;
END; -- updateGuns

我认为将:NEW中的字段复制到局部变量没有任何好处。事实上,它使代码更难以遵循,因为读者必须检查值是否与:NEW记录中的值不同。

也就是说,另一种方法是在Guns(Make, Model)上有一个唯一索引,尝试插入并使用异常忽略错误。

答案 2 :(得分:0)

有几种选择。首先,您可以使用MERGE语句处理此问题:

CREATE TRIGGER updateGuns 
  BEFORE INSERT ON GunsOwned  
  FOR EACH ROW
BEGIN
  MERGE INTO GUNS
    USING (SELECT MAKE, MODEL FROM GUNS) g
      ON (g.MAKE = :NEW.MAKEOWNED AND g.MODEL = :NEW.MODELOWNED)
  WHEN NOT MATCHED THEN
    INSERT (MAKE, MODEL)
      VALUES (:NEW.MAKEOWNED, :NEW.MODELOWNED);

 UPDATE Member
   SET NumOfGuns = NumOfGuns+1
   WHERE MemberID = :NEW.OWNERID;
END UPDATEGUNS;

在这种情况下,MERGE充当条件INSERT,如果表中尚不存在指定的品牌和型号,则只向GUNS添加新行。

或者,假设MAKE和MODEL是主键或者是GUNS上的唯一键,您可以继续执行INSERT,如果找到重复项,则捕获DUP_VAL_ON_INDEX异常,并按照您的方式快速继续:

CREATE TRIGGER updateGuns
  BEFORE INSERT ON GunsOwned  
  FOR EACH ROW
BEGIN
  BEGIN
    INSERT INTO GUNS
      (MAKE, MODEL)
    VALUES
      VALUES (:NEW.MAKEOWNED, :NEW.MODELOWNED);
  EXCEPTION
    WHEN DUP_VAL_ON_INDEX THEN
      NULL;  -- ignore the DUP_VAL_ON_INDEX exception
  END;

 UPDATE Member
   SET NumOfGuns = NumOfGuns+1
   WHERE MemberID = :NEW.OWNERID;
END UPDATEGUNS;

就个人而言,我不喜欢忽略异常 - 我宁愿编写不会引发异常的代码 - 但这是你的选择。

祝你好运。