I have the trigger:
create or replace
TRIGGER JACKET_DELETE
BEFORE DELETE ON JACKET
FOR EACH ROW
BEGIN
DELETE FROM PORT
WHERE EXISTS
(SELECT * FROM port LEFT JOIN device on port.fkdevice = device.pkid
where port.fkjacket = :old.pkid
and device.fkdevice_type = 1);
UPDATE PORT
set port.fkjacket = null, port.fkport = null
WHERE EXISTS
(SELECT port.fkjacket, port.fkport FROM port LEFT JOIN device on port.fkdevice = device.pkid
where port.fkjacket = :old.pkid
and device.fkdevice_type <> 1);
END;
For some reason, when the where in the delete matches, it deletes the WHOLE port table! I thought my SQL was correct, but obviously it’s not, and I can’t see what’s wrong with it. Can anyone see the issue that is making it do this?
When the update matches, everything works as expected.
table structure:
port links to device, jacket, and port
Your DELETE is referencing the PORT table twice. To clarify, let’s first modify the statement to include table aliases:
Notice that the subquery is not correlated to
p1. In other words, the result of this subquery will be identical for every row in PORT that is being considered for deletion. So you’re either going to delete all rows or no rows.(It’s also odd that you use a LEFT JOIN when you have a non-join predicate on the outer table. But that’s at worst an efficiency problem and more likely just confusing to anyone reading your code.)
I believe that what you want is:
And the UPDATE seems to have the same issue; even if it’s currently giving you expected results, I bet that’s just luck due to the data you’re testing with. I think it can be simplified to:
Note that an EXISTS operator doesn’t care what if any columns are returned by its subquery; just whether rows are returned at all.