Игнорировать ограничения внешнего ключа в пакетной вставке - PullRequest
6 голосов
/ 27 июня 2011

Я хочу пакетно вставить большое количество сгенерированных данных, которые имеют циклическую зависимость (столбец в каждой таблице является внешним ключом, ограниченным другой таблицей). Чтобы обойти это, я хочу просто отключить ограничения внешнего ключа, вставить данные, а затем снова включить ограничения.

Погуглив, я нашел кучу решений, но ни одно из них не сработало. Прямо сейчас у меня есть:

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 ]

11 голосов
/ 28 июня 2011

Это то, что я использовал для такой работы.

--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 голос
/ 27 июня 2011

Отключение ограничений и триггеров

См. Раздел «Отключение всех внешних ключей»

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
1 голос
/ 27 июня 2011

Вы также можете включить ON DELETE CASCADE в Ограничениях FK, что приведет к удалению их записей при каждом удалении PK из вашей основной таблицы. Это будет единовременное изменение, и вам не потребуется перезапускать его при каждой загрузке.

EDIT:

Подробнее, вот ссылка на скрипт из блога Пинала Дейва (SQLAuthority) , в котором перечислены все ограничения FK. Предложение WHERE внизу позволяет вам ограничить его определенным набором таблиц PK и FK, если это необходимо.

...