触发器有什么问题?
我用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
答案 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_id
和customer_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
大于零,够了吗?