我有触发器:
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;
Run Code Online (Sandbox Code Playgroud)
出于某种原因,当where在delete比赛中,它会删除整个port表!我认为我的SQL是正确的,但显然它不是,我看不出它有什么问题.任何人都可以看到这样做的问题吗?
当update比赛中,一切正常.
表结构:端口链接到设备,夹克和端口
您的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);
Run Code Online (Sandbox Code Playgroud)
请注意,子查询与之无关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);
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
请注意,如果子查询返回任何列,则EXISTS运算符不关心它是什么.只是是否返回行.
当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);
Run Code Online (Sandbox Code Playgroud)
这将删除端口表中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);
Run Code Online (Sandbox Code Playgroud)
这将更新端口表中的所有行,其中fkjacket位于选择列表中返回的fkjacket值列表中.
| 归档时间: |
|
| 查看次数: |
4630 次 |
| 最近记录: |