Sql 删除多对多关系中的相关行

Sql 删除多对多关系中的相关行,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我正在删除多对多关系的一个站点上的表中的一行。我还想删除该关系另一端的任何相关行 例如,假设我有以下表格,我想从汽车中删除一行。我还想删除Drivers中的任何相关行,当然还有CarDrivers中不再需要的任何行 Table Cars: CarID int CarName nvarchar(100) Table Drivers: DriverID int DriverName nvarchar(100) Table CarDrivers: CarID int

我正在删除多对多关系的一个站点上的表中的一行。我还想删除该关系另一端的任何相关行

例如,假设我有以下表格,我想从
汽车
中删除一行。我还想删除
Drivers
中的任何相关行,当然还有
CarDrivers
中不再需要的任何行

Table Cars:
CarID      int
CarName    nvarchar(100)

Table Drivers:
DriverID   int
DriverName nvarchar(100)

Table CarDrivers:
CarID      int
Driver     int
我知道如何在
SELECT
查询中连接上面的表。但我不知道如何删除关系中的数据


注意:关系的两侧都实现级联删除。因此,例如,从
Cars
中删除一行将删除
CarDrivers
中的任何相关行。但显然,这不会传播到
驱动程序表。

将级联删除放在CarDrivers表上。

如果您有权访问数据库并有权更改表,我只需创建外键并指定onupdate和oncascade,如下所示:

ALTER TABLE [dbo].[Drivers]  WITH CHECK ADD  CONSTRAINT [FK__Cars] FOREIGN KEY([CarID])
REFERENCES [dbo].[Car] ([CarID])
ON UPDATE CASCADE
ON DELETE CASCADE

ALTER TABLE [dbo].[CarDrivers]  WITH CHECK ADD  CONSTRAINT [FK_Drivers_Cars] FOREIGN KEY([CarID])
REFERENCES [dbo].[Car] ([CarID])
ON UPDATE CASCADE
ON DELETE CASCADE

这种方法的好处是,您不需要担心孤立记录。从Car表中删除一条记录时,其他表中的所有相关记录都会自动删除和更新。SQL语句也比较短。

我认为最好的方法是先删除相关表的数据。换句话说,如果你想删除一辆汽车和使用该汽车的相应司机,你必须先删除司机,然后再删除汽车。联接表将删除正确的记录,因为级联删除时出现了

试试这个:

delete
from Drivers
where DriverID in
(
    select d.DriverID
    from Drivers d
    inner join CarDrivers cd
    on d.DriverID = cd.Driver
    inner join Cars c
    on c.CarID = cd.CarID
    where c.CarID = 1
)

delete
from Cars
where CarID = 1

当然,您不需要硬编码
1
,如果您在存储过程中使用此代码段,则可以使用包括参数在内的任何内容。

您的请求没有意义

驾驶员作为实体与汽车分开存在。汽车可以由许多司机驾驶,司机可以驾驶许多汽车。这就是为什么你有很多桌子

注意“司机可以开很多车”这一点。这意味着如果删除驱动程序行,则需要删除CarDrivers中的其他行

如果你还想这样做,你需要在CarDrivers上设置一个触发器。从驱动程序到CarDrivers的级联将为您删除其他CarDrivers行。也记不起触发器递归的默认行为

真是一团糟


注意:这几乎是有意义的,如果您在多个表中的一列上具有唯一性,那么它应该是汽车和驾驶员之间的外键(汽车上的唯一性表示“每辆汽车最多一个驾驶员”表示汽车中可为空的FK列)

驾驶员和汽车表之间没有关系。这种关系是通过CarDrivers表实现的。因此,问题仍然存在

我所知道的自动级联删除的唯一方法是删除CarDrivers和Drivers表之间的FK,并向CarDrivers添加一个before或after delete触发器,以删除Drivers中的条目,其中driver_id是CarDrivers中要删除的行之一


这在很多方面都不干净。如果在联接表中实际需要删除,那么关系的建模可能是错误的,更干净的关系可能只是将关系建模为“一辆车有许多司机”或司机表中的一辆车的FK。如上所述,对于实际的汽车和驾驶员关系,多对多关系实际上是正确的,您永远不会因为汽车被合计/删除而删除驾驶员。

在Oracle中,您可以使用触发器,特别是复合触发器来处理它

alter table CarDrivers add CONSTRAINT CarFK FOREIGN KEY (CarID)
      REFERENCES Cars (CarID) on delete cascade enable
/    

create or replace TRIGGER "CarDrivers_delete"  
for delete ON CarDrivers 
compound trigger
  type driver_ids is table of Drivers.DriverID%type INDEX BY PLS_INTEGER;
  ids driver_ids;

  AFTER EACH ROW IS    
  BEGIN   
      ids (ids.COUNT + 1) := :NEW.Driver;    
  END AFTER EACH ROW;

   AFTER STATEMENT IS    
   BEGIN      
      FOR i IN 1 .. ids.COUNT    
      LOOP                                      
            delete from Drivers
             WHERE DriverID = ids (i);    
      END LOOP;    
   END AFTER STATEMENT;      
END;
/
这样就足够了

delete from Cars where CarID = 666
删除操作将通过约束级联到CarDrivers表,并通过触发器级联到Drivers表


使用复合触发器是必要的,以避免ORA-04091,即变异表错误。自Oracle11g以来,复合触发器可用

我的项目也有类似的问题(在knex和postgres中使用node.js)

然而,我的多对多表外键都不可为null,这可能与您的示例不同,因为假设数据库中可以存在一辆没有司机的汽车

由于对多对多应用了notnull、restrict和cascade,我发现按照迁移表的相反顺序分别从每个表中删除操作效果很好。使用node/knex,我将这些函数导入到需要用作回调的其他文件中,并避免重复


这可能不是最好的方式,(但足以让事情在基线上运行。

可能重复@OMG Ponies:disgree,这不是一个链接删除,因为CarDrivers to Drivers将是一个删除父项的子项。父项可能有其他子项。请参阅我的答案-1,了解误导性和不完整的问题,并提供一个只删除相关数据的坏示例在CarDrivers表中。我相信OP也希望删除作为连接一部分的相应表数据。在这种情况下,级联删除无法满足需要。Car、Drivers和CarDrivers表只是一个示例来说明我正在尝试做什么。这就是我正在使用的应用程序所做的。我将在w是您描述的,但可能不是我来更改设计。我认为这与一个表链接到其他表以及连接表包含两个附加字段有关。@Jonathan Wood:如果您需要许多表,则设计是合理的。这是一个不合理的请求,请进一步查看呃,这似乎是一对多的关系;然而,连接表的使用主要是出于我概述的原因。我可以向你保证,将孤立的项目留在关系的另一边是没有意义的。@Jonathan Wood:那么,将你的问题扩展到所有的表中,这样我们就可以正确地评论设计了。你有