Reputation: 4596
What is problem in my trigger?
I use toad for oracle
After executing this sql toad show this message and no more!:
Warning: compiled but with compilation errors
and trigger does not work
my trigger is here:
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;
/
and for deleting i receive this message:
ORA-04098: trigger 'DEVX2.TRG_DELETE_MMTP_USER_FEATURE' is invalid and failed re-validation
Upvotes: 0
Views: 6072
Reputation: 17643
The problem is
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
You're reading the table being updated/deleted, so you get mutating table error.
Maybe if you just verify that
SELECT COUNT (*)
FROM payment p
WHERE :OLD:customer_id = p.requester_id
and p.rp_reason_id = 20
is greater than zero, is enough?
Upvotes: 2
Reputation: 146219
The reason you get a compilation error is that we cannot use SELECT statements in IF clauses. So you need to break it out like this:
....
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
....
Having solved that you will find, as Florin points, that you will get a runtime mutating table error. Oracle throws this error when we put a query in a trigger which accesses the table that owns the trigger. It happens because the table is in an unstable state and the outcome of the query is unpredictable.
Mutating table errors are almost always an indicator of a bad data model, with the culprit being insufficient normalization. That means fixing them requires a knowledge of the business rules. In this case the obvious solution would be:
SELECT COUNT (*)
into n
FROM payment p
WHERE p.requester_id = :OLD.customer_id
AND p.rp_reason_id = 20
This would work if there is a one-to-one relationship between user_id
and customer_id
. It there is not such a relationship you'll have to figure out a solution using your knowledge of your business rules.
Incidentally, using COUNT(*) to test for existence is not a solution which scales. It will take a long time for a customer with many payments. That's a lot of wasted effort when all you require is that they have at least one such record. Adding and rownum = 1
into the query will reduce the needless work.
Upvotes: 5