Oracle UPDATE BEFORE TRIGGER问题:含油食谱vegetariana列禁止修改失效
原触发器存在的问题
- 语法结构错误:
DECLARE关键字必须放在PL/SQL块的BEGIN之前,原代码写在了BEGIN之后不符合Oracle语法规范 - 表名拼写错误:查询时写的表名
Ingredint是笔误,正确表名应为Ingredient - 触发变量引用错误:Oracle行级触发器中引用新旧行值必须加冒号前缀,应为
:NEW、:OLD,原代码缺少冒号 - 子查询逻辑漏洞:一个食谱可能关联多个食材,直接用
=匹配子查询返回结果,当食谱有多个食材时会抛出TOO_MANY_ROWS异常,没有匹配的oil食材时会抛出NO_DATA_FOUND异常 - 赋值语法错误:Oracle触发器中给
:NEW字段赋值不需要SET关键字,且赋值运算符为:=而非=
修正后的触发器实现
CREATE OR REPLACE TRIGGER tr_oil BEFORE UPDATE OF vegetariana ON Reteta FOR EACH ROW DECLARE has_oil NUMBER(1); BEGIN -- 检测当前食谱是否使用了oil食材 SELECT COUNT(1) INTO has_oil FROM Set_ingrediente s JOIN Ingredient i ON s.ingred_id = i.ingred_id WHERE s.reteta_id = :NEW.reteta_id AND i.ingredient = 'oil' AND ROWNUM = 1; -- 找到1条匹配即停止查询,优化性能 -- 如果使用了oil,强制vegetariana保持原值,不允许修改 IF has_oil = 1 THEN :NEW.vegetariana := :OLD.vegetariana; -- 如果需要主动抛出错误提示用户,可以取消下行注释 -- RAISE_APPLICATION_ERROR(-20001, '含油的食谱不允许修改素食标识'); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN NULL; -- 没有匹配食材时不做处理 END; /
说明:触发器添加了OF vegetariana限定,只有修改vegetariana字段时才会触发,可减少不必要的性能开销。如果希望修改任意字段时都强制校验vegetariana的值,去掉该限定即可。
内容的提问来源于stack exchange,提问作者Székely Reka
相关产品推荐
相关产品推荐

