在oracle触发器中使用SELECT检查条件

Moh*_*shi 0 oracle triggers plsql

我的触发器有什么问题?我将蟾蜍用于oracle
执行此sql蟾蜍后,显示此消息,不再!

Warning: compiled but with compilation errors
Run Code Online (Sandbox Code Playgroud)

并且触发器不起作用

我的触发器在这里:

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;
/
Run Code Online (Sandbox Code Playgroud)

对于删除,我收到此消息:

ORA-04098: trigger 'DEVX2.TRG_DELETE_MMTP_USER_FEATURE' is invalid and failed re-validation
Run Code Online (Sandbox Code Playgroud)

APC*_*APC 5

出现编译错误的原因是我们无法在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
....
Run Code Online (Sandbox Code Playgroud)

解决了您的问题,正如Florin指出的那样,您将获得运行时变异表错误。当我们在触发器中放置查询时,Oracle会访问此触发器的表,从而引发Oracle错误。发生这种情况是因为表处于不稳定状态,并且查询结果是不可预测的。

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

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

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

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