【问题标题】:Ignore Foreign Key constraints in batch insert忽略批量插入中的外键约束
【发布时间】:2011-06-27 19:08:32
【问题描述】:

我想批量插入大量生成的具有循环依赖关系的数据(每个表中的一列是约束到另一个表的外键)。为了解决这个问题,我只想关闭外键约束,插入数据,然后重新打开约束。

谷歌搜索,我找到了一堆解决方案,但都没有奏效。现在我有:

ALTER TABLE TableName NOCHECK CONSTRAINT ALL

该命令运行并且没有产生任何错误,但是当我尝试清除表以准备插入数据时,我收到以下错误:

System.Data:0:in `OnError': The DELETE statement conflicted with the REFERENCE constraint "FK_1_2_ConstraintName". The conflict occurred in database "DatabaseName", table "dbo.SomeOtherTable", column 'PrimaryKey'.\r\nThe statement has been terminated.\r\nChecking identity information: current identity value '0', current column value '0'.\r\nDBCC execution completed. If DBCC printed error messages, contact your system administrator. (System::Data::SqlClient::SqlException)

我目前的理论是,这是由另一个表上的外键约束引起的,这取决于正在更改的表。

对于这个问题,我有两种解决方案:

  1. 遍历所有依赖于我要插入的表的表,并禁用它们的外键约束。这似乎不必要地复杂。

  2. 对数据库中的所有表禁用外键约束。

任何一种解决方案都可以,但我不确定从哪一种解决方案开始。有什么想法吗?

【问题讨论】:

  • 如果两个表之间存在循环依赖关系,我会非常担心。这通常意味着您有严重的设计问题。
  • @HLGEM 不是我的设计,我无法更改它。 :|

标签: sql sql-server foreign-keys


【解决方案1】:

这是我用于此类工作的。

--Disable all Constraints 
exec sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL' 

-- INSERT DATA HERE

--Enable all Constraints 
exec sp_MSforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL' 

【讨论】:

  • 完成后,您的约束不受信任,这不好。您可能想阅读以下内容:“您能相信您的约束吗?”由 Hugo Kornelis 撰写。
  • @AlexKuznetsov:谢谢你的文章。是的,在进行此类工作时,您必须了解您的数据。就我自己而言,我只是为开发服务器执行此操作,以便从其他服务器创建测试数据。
【解决方案2】:

您还可以在 FK 约束上启用 ON DELETE CASCADE,这将导致在删除主表上的 PK 时删除它们的记录。这将是一次性更改,不需要您在每次加载时重新运行它。

编辑:

更多信息,这里有一个link to a script from Pinal Dave's blog (SQLAuthority),它列出了所有 FK 约束。如果需要,底部的 WHERE 子句可让您将其限制为特定的 PK 和 FK 表集。

【讨论】:

  • 当然,每次您想将数据清理/加载到表中时,您都会清除所有其他相关表。伙计,这似乎不是一个好的解决方案。
  • @Rodrigo - 我假设如果他正在重建他的主表记录,他将需要重新处理支持/事实表,因为该数据可能会发生变化。
【解决方案3】:

Disabling Constraints and Triggers

请参阅“禁用所有外键”部分

CREATE PROCEDURE pr_Disable_Triggers_v2 
    @disable BIT = 1
AS 
    DECLARE
        @sql VARCHAR(500),
        @tableName VARCHAR(128),
        @tableSchema VARCHAR(128)

    -- List of all tables
    DECLARE triggerCursor CURSOR
        FOR
    SELECT
        t.TABLE_NAME AS TableName,
        t.TABLE_SCHEMA AS TableSchema
    FROM
        INFORMATION_SCHEMA.TABLES t
    ORDER BY
        t.TABLE_NAME,
        t.TABLE_SCHEMA 

    OPEN triggerCursor

    FETCH NEXT FROM triggerCursor 
    INTO @tableName, @tableSchema

    WHILE ( @@FETCH_STATUS = 0 )
        BEGIN
            IF @disable = 1 
                SET @sql = ‘ALTER TABLE ‘ + @tableSchema 
                    + ‘.[‘ + @tableName + ‘] DISABLE TRIGGER ALL’ 
            ELSE 
                SET @sql = ‘ALTER TABLE ‘ + @tableSchema 
                    + ‘.[‘ + @tableName + ‘] ENABLE TRIGGER ALL’ 

            PRINT ‘Executing Statement - ‘ + @sql

            EXECUTE ( @sql )
            FETCH NEXT FROM triggerCursor
            INTO @tableName, @tableSchema
        END

    CLOSE triggerCursor
    DEALLOCATE triggerCursor

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 2011-05-15
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    相关资源
    最近更新 更多