我有触发器:
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;
出于某种原因,当where
中的delete
匹配时,它会删除整个port
表!我认为我的SQL是正确的,但显然它不是,我看不出它有什么问题。任何人都可以看到这样做的问题吗?
当update
匹配时,一切都按预期工作。
表格结构: 端口链接到设备,夹克和端口
答案 0 :(得分:8)
您的DELETE两次引用PORT表。为了澄清,我们首先修改语句以包含表别名:
DELETE FROM PORT p1
WHERE EXISTS
(SELECT * FROM port p2 LEFT JOIN device on p2.fkdevice = device.pkid
where p2.fkjacket = :old.pkid
and device.fkdevice_type = 1);
请注意,子查询与p1
无关。换句话说,对于PORT中考虑删除的每一行,此子查询的结果都是相同的。所以你要么删除所有行,要么删除没有行。
(当你在外围表上有一个非连接谓词时,使用LEFT JOIN也很奇怪。但这最糟糕的是一个效率问题,而且更可能只是让任何阅读你代码的人感到困惑。)
我相信你想要的是:
DELETE FROM PORT
WHERE fkjacket = :old.pkid
AND EXISTS
(SELECT NULL FROM device
WHERE device.pkid = port.fkdevice
AND device.fkdevice_type=1);
UPDATE似乎有同样的问题;即使它目前给你预期的结果,我敢打赌,由于您正在测试的数据,这只是运气。我认为它可以简化为:
UPDATE PORT
set port.fkjacket = null, port.fkport = null
WHERE port.fkjacket = :old.pkid
AND EXISTS
(SELECT NULL FROM device
WHERE port.fkdevice = device.pkid
AND device.fkdevice_type <> 1);
请注意,如果子查询返回任何列,则EXISTS运算符不关心它是什么。是否完全返回行。
答案 1 :(得分:5)
当fkjacket字段匹配时,您的DELETE正在删除所有内容:old.pkid,因为您没有限制删除任何其他内容。如果EXISTS子句返回一行,那么一切都会进行。
将此更改为:
DELETE FROM PORT
WHERE fkjacket IN
(SELECT port.fkjacket FROM port LEFT JOIN device on port.fkdevice = device.pkid
where port.fkjacket = :old.pkid
and device.fkdevice_type = 1);
这将删除端口表中fkjacket在选择列表中返回的fkjacket值列表中的所有行。
您确定更新是否正常运行?在我看来,你应该得到同样的行为 - 更新所有行。
编辑:
由于您的更新失败方式相同,我建议将其更改为:
UPDATE PORT
SET port.fkjacket = null, port.fkport = null
WHERE fkjacket IN
(SELECT port.fkjacket
FROM port LEFT JOIN device on port.fkdevice = device.pkid
WHERE port.fkjacket = :old.pkid
AND device.fkdevice_type <> 1);
这将更新端口表中fkjacket在选择列表中返回的fkjacket值列表中的所有行。