在oracle触发器中使用SELECT检查Condition

时间:2013-02-05 06:56:07

标签: oracle plsql triggers

触发器有什么问题? 我用toad for oracle
执行此sql toad后显示此消息而不再显示!:

Warning: compiled but with compilation errors

并且触发器不起作用

我的触发器在这里:

CREATE OR REPLACE TRIGGER trg_delete_mmtp_user_feature
   BEFORE DELETE
   ON mmtp_user
   FOR EACH ROW
BEGIN
-- for these cases delete not allowed
   IF ((SELECT COUNT (*)
          FROM payment p INNER JOIN mmtp_user mt
               ON mt.customer_id = p.requester_id
         WHERE p.rp_reason_id = 20 AND mt.mmtp_user_id = :OLD.mmtp_user_id) >
                                                                             0
      )
   THEN
      raise_application_error
             (-20654,
              'Query has attempted to delete MMTP_USER with existing payment'
             );

   ELSE                            --befor deleting features should be deleted
      DELETE FROM mmtp_user_feature
            WHERE mmtp_user_id = :OLD.mmtp_user_id;
   END IF;
END;
/

并删除我收到此消息:

ORA-04098: trigger 'DEVX2.TRG_DELETE_MMTP_USER_FEATURE' is invalid and failed re-validation

2 个答案:

答案 0 :(得分:4)

您收到编译错误的原因是我们不能在IF子句中使用SELECT语句。所以你需要像这样打破它:

....
DECLARE
    n pls_integer;
BEGIN
    SELECT COUNT (*)
    into n
    FROM payment p INNER JOIN mmtp_user mt
               ON mt.customer_id = p.requester_id
    WHERE p.rp_reason_id = 20 AND mt.mmtp_user_id = :OLD.mmtp_user_id
-- for these cases delete not allowed
   IF n > 0
   THEN
....

已经解决了,你会发现,正如弗罗林指出的那样,你会得到一个运行时变异表错误。当我们将查询放入触发器来访问拥有触发器的表时,Oracle会抛出此错误。这是因为表处于不稳定状态,并且查询的结果是不可预测的。

变异表错误几乎总是不良数据模型的指标,罪魁祸首是规范化不足。这意味着修复它们需要了解业务规则。在这种情况下,显而易见的解决方案是:

SELECT COUNT (*)
into n
FROM payment p 
WHERE p.requester_id = :OLD.customer_id
AND p.rp_reason_id = 20 

如果user_idcustomer_id之间存在一对一的关系,这将有效。没有这种关系,您必须使用您对业务规则的了解来找出解决方案。

顺便说一句,使用COUNT(*)来测试存在并不是一种可扩展的解决方案。付款很多的客户需要很长时间。当你需要的是他们至少一个这样的记录时,这就浪费了很多。将and rownum = 1添加到查询中将减少不必要的工作。

答案 1 :(得分:2)

问题是

   SELECT COUNT (*)
              FROM payment p INNER JOIN mmtp_user mt
                   ON mt.customer_id = p.requester_id
             WHERE p.rp_reason_id = 20 AND mt.mmtp_user_id = :OLD.mmtp_user_id

您正在阅读正在更新/删除的表,因此您会发生变异表错误。

也许你只是验证

SELECT COUNT (*)
          FROM payment p 
          WHERE :OLD:customer_id = p.requester_id
            and p.rp_reason_id = 20  

大于零,够了吗?