在表“ tblMaintenance”上引入FOREIGN KEY约束“ FK2CustomerId”可能会导致循环或多个级联路径

时间:2018-08-11 05:09:09

标签: sql-server

我创建了一个与2个其他表有关系的表。但是,当我尝试从另一个表连接FK时,会显示以下警告:

  

在表'tblMaintenance'上引入FOREIGN KEY约束'FK1VehicleID'可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束

这是我写的:

CREATE TABLE tblMaintenance
(  
    MaintenanceID Int Identity(1,1) Primary Key,
    Description VarChar(100),
    Date Date,
    TotalAmount Money, 
    VehicleID Int,
    CustomerID Int, 
    PurchaseID Int,

    Constraint FK2CustomerID 
        Foreign Key(CustomerID) References tblCustomer(CustomerID)
            ON DELETE Cascade On Update Cascade,
    Constraint FK1VehicleID 
        Foreign Key(VehicleID) References tblVehicle(VehicleID)
            ON DELETE Cascade On Update Cascade,
)
Go

以下是与上述陈述有关的另一项陈述:

 --**Table tblCustomer
 Create Table tblCustomer
(
  CustomerID Int Identity(1,1) Primary Key,
  CustomerName VarChar(30),
  Address VarChar(150),
  Phone VarChar(30)
)
Go
---------------End Table tblCustomer------------------------------------
--**Table tblVehicle
Create Table tblVehicle
(
  VehicleID Int Identity(1,1) Primary Key,
  Brand VarChar(30), 
  PlateNumber VarChar(30), 
  EngineNumber VarChar(30),
  CustomerID Int, 
  CustomerName VarChar(30),

  Constraint FK1CustomerID 
      ForeignKey(CustomerID) References tblCustomer(CustomerID)
            On Delete Cascade On Update Cascade
)
Go
---------------End Table tblVehicle------------------------------------

1 个答案:

答案 0 :(得分:0)

美好的一天,

  

在SQL Server中,表在由DELETE或UPDATE语句启动的所有级联引用动作的列表中不能出现多次。

有关完整说明,简单的解决方法和更多信息,请转到此处的官方文档(这是上面引用的来源): https://support.microsoft.com/en-ca/help/321843/error-message-1785-occurs-when-you-create-a-foreign-key-constraint-tha

-----更新以色列时间2018-08-12 22:40 ------

我将尝试解释Microsoft团队选择阻止这种结构的原因...

让我们假设我们有以下三个表:

DROP TABLE IF EXISTS A;
create table A (Aid NVARCHAR(3) primary key)
GO

DROP TABLE IF EXISTS B;
Create Table B(
    Bid NVARCHAR(3) primary key,
    Aid NVARCHAR(3)
)
Go

DROP TABLE IF EXISTS C;
Create Table C(
    Cid NVARCHAR(3) primary key,
    Aid NVARCHAR(3),
    Bid NVARCHAR(3)
)
Go

Insert A(Aid) values ('a1'),('a2'),('a3'),('a4')
Insert B(Bid, Aid) values ('b1','a1'),('b2','a1'),('b3','a2')
Insert C(Cid,Bid, Aid) values ('c1','b1','a2'),('c2','b1','a2'),('c3','b2','a2'),('c4','b3','a4')
GO

SELECT * FROM A
SELECT * FROM B
SELECT * FROM C
GO

考虑一下一种情况,即根据列名称这些表之间存在硬关系(使用FOREIGN KEY),而这些FK则为“在更新级联上删除级联”。

  1. 现在让我们从表A中删除行a1
  2. 由于我们从表B配置了FK级联,因此应删除表B中的相关行:这意味着应删除行b1,b2
  3. 但是由于表C的FK为B,因此我们需要将表C中的相关行删除到b1,b2。这意味着我们删除行c1,c2和c3
  4. 现在我们有了问题!由于表C也与表A有关,因此我们删除了与行a2有关的行c3(我们没有删除)!现在,这个问题引起了对表A中的a2行的处理。我们删除了他的孩子,所以让我们删除它...
  5. 一秒钟...问题继续...现在我们删除了表A中的行a2。因此,我们需要删除表B中的行b3,因此我们需要删除表C中的行c4 ...

从理论上讲,没有任何限制,可以继续执行此任务,直到完成为止。有数据库服务器允许这种结构。

话虽如此,当我们只想删除一行并进入删除循环时,这种情况会导致性能很差,并且在删除内容方面造成混乱。如果我们也想使用Cascade,SQL Server将不允许设计这种结构!为了防止出现这种情况,SQL Server团队选择防止这种结构以及自动删除(在Delete Cascade上)。实际上,如果您以正确的方式设计数据库,我们可能就不会达到这一要求。

  

注意!这种情况就是所谓的“多级联路径”,与无限循环的情况相比并不极端。

     

注意!我在这里使用DELETE进行检查,但是相同的问题和相同的规则也与UPDATE有关。如果必须具有此结构,则可以删除级联并自己控制子级中的删除。