我一直在尝试找到在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;
有人可以帮忙吗?
谢谢!
答案 0 :(得分:0)
使用简单的INSERT ... SELECT ... WHERE而不是CASE
或IF
语句:
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;
就个人而言,我不喜欢忽略异常 - 我宁愿编写不会引发异常的代码 - 但这是你的选择。
祝你好运。