批量插入中忽略外键约束

时间:2011-06-27 19:08:33

标签: sql sql-server foreign-keys

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

谷歌搜索,我发现了一堆解决方案,但没有一个有效。现在我有:

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. 禁用数据库中所有表的外键约束。

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

3 个答案:

答案 0 :(得分:11)

这就是我用于此类工作的内容。

--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' 

答案 1 :(得分:1)

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

修改

更多信息,这里是列出所有FK约束的link to a script from Pinal Dave's blog (SQLAuthority)。底部的WHERE子句允许您根据需要将其限制为某个PK和FK表集。

答案 2 :(得分:1)

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