【问题标题】:Sql error on update : The UPDATE statement conflicted with the FOREIGN KEY constraint更新时出现 Sql 错误:UPDATE 语句与 FOREIGN KEY 约束冲突
【发布时间】:2014-07-14 10:02:30
【问题描述】:

我有一个名为patient_address 的表,它引用patient 表中的一个PK 键。但是,如果我尝试运行以下语句之一:

update patient set id_no='7008255601088' where id_no='8008255601089'
update patient_address set id_no='7008255601088' where id_no='8008255601089'

我收到此错误消息:

"UPDATE 语句与 REFERENCE 约束冲突 “FK__patient_a__id_no__27C3E46E”。数据库发生冲突 "PMS",表 "dbo.patient_address",列 'id_no'。" 或 "The UPDATE 语句与 FOREIGN KEY 约束冲突 “FK__patient_a__id_no__27C3E46E”。数据库发生冲突 “PMS”,表“dbo.patient”,列“id_no”。”。

有没有人知道可能的原因?谢谢。

【问题讨论】:

  • dbo.patient_address.id_no 允许NULLs ?如果是,那么您可以将dbo.patient_address.id_no 设置为NULL,更新dbo.patient.id_no,然后将dbo.patient_address.id_no 设置为新值。
  • 是的。这是可能的原因吗?
  • 没有。这不是原因。是解决方案。
  • 问题是答案 4 中的级联问题。我现在已排序。谢谢
  • 我希望你知道你在做什么。

标签: sql-server


【解决方案1】:

当一个表的主键被更新但它被另一个表的外键引用并且更新特定设置为无操作时会遇到此错误。无操作是默认选项。

如果这是您的情况并且没有对更新操作设置任何操作,您可以将外键定义更改为级联。

右键单击您的外键并选择修改。在 INSERT 和 UPDATE 细节下的外键关系对话框中,在 Cascade 上设置 UPDATE 规则:

您也可以使用 T-SQL 设置规则:

ALTER TABLE YourTable
DROP Constraint Your_FK
GO

ALTER TABLE YourTable
ADD CONSTRAINT [New_FK_Constraint]
FOREIGN KEY (YourColumn) REFERENCES ReferencedTable(YourColumn)
ON DELETE CASCADE ON UPDATE CASCADE
GO 

希望对你有帮助

【讨论】:

  • 我已按照您在此处的建议设置了“更新级联时删除级联”。我仍然遇到同样的错误。你有什么想法吗?
  • @KushanRandima 确保更新主键表,而不是依赖表。例如,如果订单引用用户,请执行UPDATE User SET Id = ...,而不是UPDATE Order SET UserID = ....
  • 为我节省了在更新语句后删除所有约束并重新创建它们的工作。节省时间!
  • 如何在 Visual Studio 2019 中打开该外键关系对话框?有人吗?
  • @Zheng-rongCai 该对话框来自 SQL Server Management Studio。
【解决方案2】:

如果您不想更改表结构,可以运行以下查询:

ALTER TABLE [UserStore] 
NOCHECK CONSTRAINT FK_UserStore_User_UserId

ALTER TABLE [UserIdentity]
NOCHECK CONSTRAINT  FK_UserIdentity_User_UserId

BEGIN TRAN

UPDATE  [user] 
SET Id = 10
WHERE Id = 9

UPDATE  [dbo].[UserStore]
SET UserId = 10
WHERE UserId = 9

UPDATE  [dbo].UserIdentity
SET UserId = 10
WHERE UserId = 9

COMMIT TRAN

ALTER TABLE [UserStore] 
CHECK CONSTRAINT FK_UserStore_User_UserId

ALTER TABLE UserIdentity 
CHECK CONSTRAINT FK_UserIdentity_User_UserId

【讨论】:

    【解决方案3】:

    如果dbo.patient_address.id_no 列允许NULLs,那么您可以使用此解决方案:

    SET XACT_ABORT ON;
    BEGIN TRANSACTION;
    
    -- I assmume that [id] is the primary key of patient_address table (single column key)
    -- replace the name of [id] column with the name of PK column from patient_address table
    -- replace INT data type with the proper type
    DECLARE @RowsForUpdate TABLE([id] INT PRIMARY KEY); 
    UPDATE patient_address 
    SET id_no = NULL
    OUTPUT deleted.[id] INTO @RowsForUpdate ([id])
    WHERE id_no='8008255601088'
    
    UPDATE patient 
    SET id_no='7008255601088' 
    WHERE id_no='8008255601088'
    
    UPDATE patient_address 
    SET id_no='7008255601088' 
    WHERE [id] IN (SELECT u.[id] FROM @RowsForUpdate u)
    
    COMMIT;
    

    【讨论】:

      【解决方案4】:

      在 MySQL 中

      set foreign_key_checks=0;
      
      UPDATE patient INNER JOIN patient_address 
      ON patient.id_no=patient_address.id_no 
      SET patient.id_no='8008255601088', 
      patient_address.id_no=patient.id_no 
      WHERE patient.id_no='7008255601088';
      

      请注意,foreign_key_checks 只是暂时将外键检查设置为 false。所以它需要在每次更新语句之前执行。我们将其设置为 0,就好像我们首先更新父级然后不允许这样做,因为子级可能已经具有该值。如果我们先更新孩子,那么这也是不允许的,因为父母可能没有我们正在更新的那个值。所以我们需要设置外键检查。 另一件事是,如果您使用命令行工具来使用此查询,那么请注意在我在代码中放置新行或 ENTER 的位置提及空格。由于命令行将它放在一行中,因此可能会发生两个单词粘贴为 patient_addressON 从而产生语法错误。

      【讨论】:

        【解决方案5】:

        这就是我的解决方案:

        -- Check how it is now
        select * from patient
        select * from patient_address
        
        -- Alter your DB
        alter table patient_address nocheck constraint FK__patient_a__id_no__27C3E46E
        update patient 
        set id_no='7008255601088'
        where id_no='8008255601088'
        
        alter table patient_address nocheck constraint FK__patient_a__id_no__27C3E46E
        update patient_address 
        set id_no='7008255601088'
        where id_no='8008255601088'
        
        -- Check how it is now
        select * from patient
        select * from patient_address
        

        【讨论】:

          【解决方案6】:

          原因正如@MilicaMedic 所说。替代解决方案是禁用所有约束,进行更新,然后像这样再次启用约束。在测试环境中更新测试数据时非常有用。

          exec sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
          
          update patient set id_no='7008255601088' where id_no='8008255601088'
          update patient_address set id_no='7008255601088' where id_no='8008255601088'
          
          exec sp_MSforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
          

          来源:

          https://stackoverflow.com/a/161410/3850405

          【讨论】:

            【解决方案7】:

            我不会改变约束, 相反,您可以使用主键 (id_no = 7008255601088) 在 table_1 中插入一条新记录。这只不过是 id_no = 8008255601088 的重复行。所以现在可以更新具有外键约束(id_no = 8008255601088)的患者地址以指向具有新 ID(需要更新的 ID)的记录,该记录正在更新id_no 到 id_no =7008255601088。

            然后,您可以删除 id_no =7008255601088 的初始主键行。

            三个步骤包括:

            1. 为新的 id_no 插入重复行
            2. 更新 Patient_address 以指向新的重复行
            3. 删除旧 id_no 的行

            【讨论】:

              【解决方案8】:

              我猜如果你改变id_no,一些外键不会引用任何东西,因此违反了约束。 您可以将initialy deffered 添加到外键中,以便在提交更改时检查约束

              【讨论】:

              • 根据此链接:stackoverflow.com/questions/998095/…,SQL Server 不支持延迟。这是真的 ?我正忙于弄清楚如何在外键上应用 Defered
              • 这取决于服务器,我认为 postgrsql 支持它。对于其他服务器,我不知道
              • 很遗憾我的服务器不支持 postgrsql。
              【解决方案9】:

              当您尝试Insert/Update 一个实体而您尝试Insert/Updateforeign key 实际上不存在 时,有时会发生这种情况。因此,请确保 foreign key 存在并重试。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2023-03-06
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多