2008-10-01 1 views
717

Отключить и включить ограничения внешнего ключа, поддерживаемые в SQL Server? Или мой единственный вариант: drop, а затем create Ограничения?Как можно ограничить внешние ключи с помощью T-SQL?

+114

Для людей, спрашивающих «почему», я хотел бы сделать это: это для тестовой среды, где я хочу иметь возможность удалять и загружать тестовые данные из нескольких таблиц без необходимости поддерживать и указывать порядок использования данных загружен. Целостность данных не так важна для этого сценария. – 2008-10-01 18:48:36

+5

Примечание. Если вы хотите ПРОВЕРИТЬ таблицу, вам действительно нужно отказаться от ограничений. – OutstandingBill 2016-07-02 01:11:17

ответ

994

Если вы хотите, чтобы отключить все ограничения в базе данных просто запустите этот код:

-- disable all constraints 
EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all" 

Чтобы включить их обратно, выполните: (печать не является обязательным, конечно, и это просто перечисление таблиц)

-- enable all constraints 
exec sp_MSforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all" 

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

Если вы удаляете все данные, вы можете найти this solution, чтобы быть полезным.

Также иногда удобно отключать все триггеры, вы можете увидеть полное решение here.

340

http://www.sqljunkies.com/WebLog/roman/archive/2005/01/30/7037.aspx

-- Disable all table constraints 

ALTER TABLE MyTable NOCHECK CONSTRAINT ALL 

-- Enable all table constraints 

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT ALL 

-- Disable single constraint 

ALTER TABLE MyTable NOCHECK CONSTRAINT MyConstraint 

-- Enable single constraint 

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint 
+25

хорошая находка, но обратите внимание, что вы по-прежнему не можете обрезать таблицу без удаления ограничений внешнего ключа – 2008-10-01 18:41:25

+1

, и вам также нужно будет знать, что когда вы снова включаете ограничения и выполняете проверку целостности данных, ваши данные могут терпеть неудачу и исправить подобная проблема может быть кошмаром, если неудачные данные находятся в конце длинной строки связанных ограничений. – Jimoc 2008-10-01 18:44:13

+0

my sql server 2008 просит проверить чек, а не проверять и проверять nocheck – Omu 2011-03-10 13:48:00

9

В стандарте SQL-92 допускается, чтобы константа была объявлена ​​как DEFERRABLE, чтобы ее можно было отложить (неявно или явно) в рамках транзакции. К сожалению, SQL Server по-прежнему не хватает этой функциональности SQL-92.

Для меня изменение ограничения на NOCHECK сродни изменению структуры базы данных на лету - исключение ограничений - и что-то, чего следует избегать (например, пользователям требуются повышенные привилегии).

8
--Drop and Recreate Foreign Key Constraints 

SET NOCOUNT ON 

DECLARE @table TABLE(
    RowId INT PRIMARY KEY IDENTITY(1, 1), 
    ForeignKeyConstraintName NVARCHAR(200), 
    ForeignKeyConstraintTableSchema NVARCHAR(200), 
    ForeignKeyConstraintTableName NVARCHAR(200), 
    ForeignKeyConstraintColumnName NVARCHAR(200), 
    PrimaryKeyConstraintName NVARCHAR(200), 
    PrimaryKeyConstraintTableSchema NVARCHAR(200), 
    PrimaryKeyConstraintTableName NVARCHAR(200), 
    PrimaryKeyConstraintColumnName NVARCHAR(200)  
) 

INSERT INTO @table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName) 
SELECT 
    U.CONSTRAINT_NAME, 
    U.TABLE_SCHEMA, 
    U.TABLE_NAME, 
    U.COLUMN_NAME 
FROM 
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE U 
     INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C 
     ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME 
WHERE 
    C.CONSTRAINT_TYPE = 'FOREIGN KEY' 

UPDATE @table SET 
    PrimaryKeyConstraintName = UNIQUE_CONSTRAINT_NAME 
FROM 
    @table T 
     INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R 
     ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME 

UPDATE @table SET 
    PrimaryKeyConstraintTableSchema = TABLE_SCHEMA, 
    PrimaryKeyConstraintTableName = TABLE_NAME 
FROM @table T 
    INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C 
     ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME 

UPDATE @table SET 
    PrimaryKeyConstraintColumnName = COLUMN_NAME 
FROM @table T 
    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U 
     ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME 

--SELECT * FROM @table 

--DROP CONSTRAINT: 
SELECT 
    ' 
    ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
    DROP CONSTRAINT ' + ForeignKeyConstraintName + ' 

    GO' 
FROM 
    @table 

--ADD CONSTRAINT: 
SELECT 
    ' 
    ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
    ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ') 

    GO' 
FROM 
    @table 

GO 

Я согласен с вами, Хэмлин. Когда вы передаете данные с помощью SSIS или когда хотите реплицировать данные, представляется необходимым временно отключить или отключить ограничения внешнего ключа, а затем снова включить или воссоздать их. В этих случаях ссылочная целостность не является проблемой, поскольку она уже поддерживается в исходной базе данных. Поэтому вы можете быть уверены в этом.

9
SET NOCOUNT ON 

DECLARE @table TABLE(
    RowId INT PRIMARY KEY IDENTITY(1, 1), 
    ForeignKeyConstraintName NVARCHAR(200), 
    ForeignKeyConstraintTableSchema NVARCHAR(200), 
    ForeignKeyConstraintTableName NVARCHAR(200), 
    ForeignKeyConstraintColumnName NVARCHAR(200), 
    PrimaryKeyConstraintName NVARCHAR(200), 
    PrimaryKeyConstraintTableSchema NVARCHAR(200), 
    PrimaryKeyConstraintTableName NVARCHAR(200), 
    PrimaryKeyConstraintColumnName NVARCHAR(200), 
    UpdateRule NVARCHAR(100), 
    DeleteRule NVARCHAR(100) 
) 

INSERT INTO @table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName) 
SELECT 
    U.CONSTRAINT_NAME, 
    U.TABLE_SCHEMA, 
    U.TABLE_NAME, 
    U.COLUMN_NAME 
FROM 
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE U 
     INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C 
     ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME 
WHERE 
    C.CONSTRAINT_TYPE = 'FOREIGN KEY' 

UPDATE @table SET 
    T.PrimaryKeyConstraintName = R.UNIQUE_CONSTRAINT_NAME, 
    T.UpdateRule = R.UPDATE_RULE, 
    T.DeleteRule = R.DELETE_RULE 
FROM 
    @table T 
     INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R 
     ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME 

UPDATE @table SET 
    PrimaryKeyConstraintTableSchema = TABLE_SCHEMA, 
    PrimaryKeyConstraintTableName = TABLE_NAME 
FROM @table T 
    INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C 
     ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME 

UPDATE @table SET 
    PrimaryKeyConstraintColumnName = COLUMN_NAME 
FROM @table T 
    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U 
     ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME 

--SELECT * FROM @table 

SELECT ' 
BEGIN TRANSACTION 
BEGIN TRY' 

--DROP CONSTRAINT: 
SELECT 
    ' 
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
DROP CONSTRAINT ' + ForeignKeyConstraintName + ' 
    ' 
FROM 
    @table 

SELECT ' 
END TRY 

BEGIN CATCH 
    ROLLBACK TRANSACTION 
    RAISERROR(''Operation failed.'', 16, 1) 
END CATCH 

IF(@@TRANCOUNT != 0) 
BEGIN 
    COMMIT TRANSACTION 
    RAISERROR(''Operation completed successfully.'', 10, 1) 
END 
' 

--ADD CONSTRAINT: 
SELECT ' 
BEGIN TRANSACTION 
BEGIN TRY' 

SELECT 
    ' 
    ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
    ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ') ON UPDATE ' + UpdateRule + ' ON DELETE ' + DeleteRule + ' 
    ' 
FROM 
    @table 

SELECT ' 
END TRY 

BEGIN CATCH 
    ROLLBACK TRANSACTION 
    RAISERROR(''Operation failed.'', 16, 1) 
END CATCH 

IF(@@TRANCOUNT != 0) 
BEGIN 
    COMMIT TRANSACTION 
    RAISERROR(''Operation completed successfully.'', 10, 1) 
END' 

GO 
17

Чтобы отключить ограничение, вы должны изменить таблицу с помощью NOCHECK

ALTER TABLE [TABLE_NAME] NOCHECK CONSTRAINT [ALL|CONSTRAINT_NAME] 

Для включения необходимо использовать двойной CHECK

ALTER TABLE [TABLE_NAME] WITH CHECK CHECK CONSTRAINT [ALL|CONSTRAINT_NAME] 
  • Обратите внимание на двойной ПРОВЕРКА ПРОВЕРКА при включении.
  • ВСЕ средства для всех ограничений в таблице.

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

24

Ваш лучший вариант - DROP и CREATE ограничения внешнего ключа.

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

Вот скрипт, который генерирует «ADD Constraint» заявления, для нескольких столбцов будет разделять их запятой (не забудьте сохранить этот вывод перед выполнением операторы DROP):

PRINT N'-- CREATE FOREIGN KEY CONSTRAINTS --'; 

SET NOCOUNT ON; 
SELECT ' 
PRINT N''Creating '+ const.const_name +'...'' 
GO 
ALTER TABLE ' + const.parent_obj + ' 
    ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
      ' + const.parent_col_csv + ' 
      ) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ') 
GO' 
FROM (
    SELECT QUOTENAME(fk.NAME) AS [const_name] 
     ,QUOTENAME(schParent.NAME) + '.' + QUOTENAME(OBJECT_name(fkc.parent_object_id)) AS [parent_obj] 
     ,STUFF((
       SELECT ',' + QUOTENAME(COL_NAME(fcP.parent_object_id, fcp.parent_column_id)) 
       FROM sys.foreign_key_columns AS fcP 
       WHERE fcp.constraint_object_id = fk.object_id 
       FOR XML path('') 
       ), 1, 1, '') AS [parent_col_csv] 
     ,QUOTENAME(schRef.NAME) + '.' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)) AS [ref_obj] 
     ,STUFF((
       SELECT ',' + QUOTENAME(COL_NAME(fcR.referenced_object_id, fcR.referenced_column_id)) 
       FROM sys.foreign_key_columns AS fcR 
       WHERE fcR.constraint_object_id = fk.object_id 
       FOR XML path('') 
       ), 1, 1, '') AS [ref_col_csv] 
    FROM sys.foreign_key_columns AS fkc 
    INNER JOIN sys.foreign_keys AS fk ON fk.object_id = fkc.constraint_object_id 
    INNER JOIN sys.objects AS oParent ON oParent.object_id = fkc.parent_object_id 
    INNER JOIN sys.schemas AS schParent ON schParent.schema_id = oParent.schema_id 
    INNER JOIN sys.objects AS oRef ON oRef.object_id = fkc.referenced_object_id 
    INNER JOIN sys.schemas AS schRef ON schRef.schema_id = oRef.schema_id 
    GROUP BY fkc.parent_object_id 
     ,fkc.referenced_object_id 
     ,fk.NAME 
     ,fk.object_id 
     ,schParent.NAME 
     ,schRef.NAME 
    ) AS const 
ORDER BY const.const_name 

Вот скрипт, который генерирует "DROP Constraint" заявления:

PRINT N'-- DROP FOREIGN KEY CONSTRAINTS --'; 

SET NOCOUNT ON; 

SELECT ' 
PRINT N''Dropping ' + fk.NAME + '...'' 
GO 
ALTER TABLE [' + sch.NAME + '].[' + OBJECT_NAME(fk.parent_object_id) + ']' + ' DROP CONSTRAINT ' + '[' + fk.NAME + '] 
GO' 
FROM sys.foreign_keys AS fk 
INNER JOIN sys.schemas AS sch ON sch.schema_id = fk.schema_id 
ORDER BY fk.NAME 
5

Найти ограничение

SELECT * 
FROM sys.foreign_keys 
WHERE referenced_object_id = object_id('TABLE_NAME') 

Выполнить SQL, генерируемый этим SQL

SELECT 
    'ALTER TABLE ' + OBJECT_SCHEMA_NAME(parent_object_id) + 
    '.[' + OBJECT_NAME(parent_object_id) + 
    '] DROP CONSTRAINT ' + name 
FROM sys.foreign_keys 
WHERE referenced_object_id = object_id('TABLE_NAME') 

Safeway.

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

7

Первый пост :)

Для ОП, решения Krištof будет работать, если нет проблем с массивными данными и вопросами журнала транзакций на воздушном шаре на больших удалениях. Кроме того, даже с сохранением хранилища tlog, так как удаляет запись в tlog, операция может занять очень много времени для таблиц с сотнями миллионов строк.

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

Он включает в себя создание трех промежуточных таблиц (реальных таблиц) для размещения сценариев DROP, CREATE и CHECK FK, создания и вставки этих скриптов в таблицы, а затем циклического перемещения по ним и их выполнения. Приложенный сценарий состоит из четырех частей: 1.) создание и хранение сценариев в трех промежуточных (реальных) таблицах, 2.) выполнение сценариев FK сбрасывания с помощью курсора один за другим, 3.) использование sp_MSforeachtable для усечения всех таблицы в базе данных, отличные от наших трех промежуточных таблиц, и 4.) выполнение создания FK и проверка скриптов FK в конце вашего пакета SSIS ETL.

Запустить часть создания скрипта в выполнении задачи SQL в SSIS. Запустите «execute Drop FK Scripts» во второй задаче Execute SQL. Поместите скрипт усечения в третью задачу SQL Execute, затем выполните все другие процессы ETL, которые необходимо выполнить, перед тем, как присоединить сценарии CREATE и CHECK в конечной задаче Execute SQL (или два, если требуется) в конце вашего потока управления.

Хранение скриптов в реальных таблицах оказалось неоценимым, если повторное применение внешних ключей не удалось, поскольку вы можете выбрать * из sync_CreateFK, скопировать/вставить в окно запроса, запустить их по одному и исправить когда вы найдете те, которые не удались/все еще не могут повторно применяться.

Не перезапускайте сценарий еще раз, если он не работает, не убедившись, что вы повторно примените все внешние ключи/проверки до этого, или вы скорее всего потеряете некоторое создание и проверите скрипты fk как наш этап таблицы отбрасываются и воссоздаются до создания сценариев для выполнения.

---------------------------------------------------------------------------- 
1) 
/* 
Author:   Denmach 
DateCreated: 2014-04-23 
Purpose:  Generates SQL statements to DROP, ADD, and CHECK existing constraints for a 
       database. Stores scripts in tables on target database for execution. Executes 
       those stored scripts via independent cursors. 
DateModified: 
ModifiedBy 
Comments:  This will eliminate deletes and the T-log ballooning associated with it. 
*/ 

DECLARE @schema_name SYSNAME; 
DECLARE @table_name SYSNAME; 
DECLARE @constraint_name SYSNAME; 
DECLARE @constraint_object_id INT; 
DECLARE @referenced_object_name SYSNAME; 
DECLARE @is_disabled BIT; 
DECLARE @is_not_for_replication BIT; 
DECLARE @is_not_trusted BIT; 
DECLARE @delete_referential_action TINYINT; 
DECLARE @update_referential_action TINYINT; 
DECLARE @tsql NVARCHAR(4000); 
DECLARE @tsql2 NVARCHAR(4000); 
DECLARE @fkCol SYSNAME; 
DECLARE @pkCol SYSNAME; 
DECLARE @col1 BIT; 
DECLARE @action CHAR(6); 
DECLARE @referenced_schema_name SYSNAME; 



--------------------------------Generate scripts to drop all foreign keys in a database -------------------------------- 

IF OBJECT_ID('dbo.sync_dropFK') IS NOT NULL 
DROP TABLE sync_dropFK 

CREATE TABLE sync_dropFK 
    (
    ID INT IDENTITY (1,1) NOT NULL 
    , Script NVARCHAR(4000) 
    ) 

DECLARE FKcursor CURSOR FOR 

    SELECT 
     OBJECT_SCHEMA_NAME(parent_object_id) 
     , OBJECT_NAME(parent_object_id) 
     , name 
    FROM 
     sys.foreign_keys WITH (NOLOCK) 
    ORDER BY 
     1,2; 

OPEN FKcursor; 

FETCH NEXT FROM FKcursor INTO 
    @schema_name 
    , @table_name 
    , @constraint_name 

WHILE @@FETCH_STATUS = 0 

BEGIN 
     SET @tsql = 'ALTER TABLE ' 
       + QUOTENAME(@schema_name) 
       + '.' 
       + QUOTENAME(@table_name) 
       + ' DROP CONSTRAINT ' 
       + QUOTENAME(@constraint_name) 
       + ';'; 
    --PRINT @tsql; 
    INSERT sync_dropFK (
         Script 
         ) 
         VALUES (
           @tsql 
           ) 

    FETCH NEXT FROM FKcursor INTO 
    @schema_name 
    , @table_name 
    , @constraint_name 
    ; 

END; 

CLOSE FKcursor; 

DEALLOCATE FKcursor; 


---------------Generate scripts to create all existing foreign keys in a database -------------------------------- 
---------------------------------------------------------------------------------------------------------- 
IF OBJECT_ID('dbo.sync_createFK') IS NOT NULL 
DROP TABLE sync_createFK 

CREATE TABLE sync_createFK 
    (
    ID INT IDENTITY (1,1) NOT NULL 
    , Script NVARCHAR(4000) 
    ) 

IF OBJECT_ID('dbo.sync_createCHECK') IS NOT NULL 
DROP TABLE sync_createCHECK 

CREATE TABLE sync_createCHECK 
    (
    ID INT IDENTITY (1,1) NOT NULL 
    , Script NVARCHAR(4000) 
    ) 

DECLARE FKcursor CURSOR FOR 

    SELECT 
     OBJECT_SCHEMA_NAME(parent_object_id) 
     , OBJECT_NAME(parent_object_id) 
     , name 
     , OBJECT_NAME(referenced_object_id) 
     , OBJECT_ID 
     , is_disabled 
     , is_not_for_replication 
     , is_not_trusted 
     , delete_referential_action 
     , update_referential_action 
     , OBJECT_SCHEMA_NAME(referenced_object_id) 

    FROM 
     sys.foreign_keys WITH (NOLOCK) 

    ORDER BY 
     1,2; 

OPEN FKcursor; 

FETCH NEXT FROM FKcursor INTO 
    @schema_name 
    , @table_name 
    , @constraint_name 
    , @referenced_object_name 
    , @constraint_object_id 
    , @is_disabled 
    , @is_not_for_replication 
    , @is_not_trusted 
    , @delete_referential_action 
    , @update_referential_action 
    , @referenced_schema_name; 

WHILE @@FETCH_STATUS = 0 

BEGIN 

     BEGIN 
      SET @tsql = 'ALTER TABLE ' 
         + QUOTENAME(@schema_name) 
         + '.' 
         + QUOTENAME(@table_name) 
         + CASE 
           @is_not_trusted 
           WHEN 0 THEN ' WITH CHECK ' 
           ELSE ' WITH NOCHECK ' 
          END 
         + ' ADD CONSTRAINT ' 
         + QUOTENAME(@constraint_name) 
         + ' FOREIGN KEY ('; 

     SET @tsql2 = ''; 

     DECLARE ColumnCursor CURSOR FOR 

      SELECT 
       COL_NAME(fk.parent_object_id 
       , fkc.parent_column_id) 
       , COL_NAME(fk.referenced_object_id 
       , fkc.referenced_column_id) 

      FROM 
       sys.foreign_keys fk WITH (NOLOCK) 
       INNER JOIN sys.foreign_key_columns fkc WITH (NOLOCK) ON fk.[object_id] = fkc.constraint_object_id 

      WHERE 
       fkc.constraint_object_id = @constraint_object_id 

      ORDER BY 
       fkc.constraint_column_id; 

     OPEN ColumnCursor; 

     SET @col1 = 1; 

     FETCH NEXT FROM ColumnCursor INTO @fkCol, @pkCol; 

     WHILE @@FETCH_STATUS = 0 

     BEGIN 
      IF (@col1 = 1) 
       SET @col1 = 0; 
      ELSE 
      BEGIN 
       SET @tsql = @tsql + ','; 
       SET @tsql2 = @tsql2 + ','; 
      END; 

      SET @tsql = @tsql + QUOTENAME(@fkCol); 
      SET @tsql2 = @tsql2 + QUOTENAME(@pkCol); 
      --PRINT '@tsql = ' + @tsql 
      --PRINT '@tsql2 = ' + @tsql2 
      FETCH NEXT FROM ColumnCursor INTO @fkCol, @pkCol; 
      --PRINT 'FK Column ' + @fkCol 
      --PRINT 'PK Column ' + @pkCol 
     END; 

     CLOSE ColumnCursor; 
     DEALLOCATE ColumnCursor; 

     SET @tsql = @tsql + ') REFERENCES ' 
        + QUOTENAME(@referenced_schema_name) 
        + '.' 
        + QUOTENAME(@referenced_object_name) 
        + ' (' 
        + @tsql2 + ')'; 

     SET @tsql = @tsql 
        + ' ON UPDATE ' 
        + 
         CASE @update_referential_action 
          WHEN 0 THEN 'NO ACTION ' 
          WHEN 1 THEN 'CASCADE ' 
          WHEN 2 THEN 'SET NULL ' 
           ELSE 'SET DEFAULT ' 
         END 

        + ' ON DELETE ' 
        + 
         CASE @delete_referential_action 
          WHEN 0 THEN 'NO ACTION ' 
          WHEN 1 THEN 'CASCADE ' 
          WHEN 2 THEN 'SET NULL ' 
           ELSE 'SET DEFAULT ' 
         END 

        + 
        CASE @is_not_for_replication 
         WHEN 1 THEN ' NOT FOR REPLICATION ' 
          ELSE '' 
        END 
        + ';'; 

     END; 

    -- PRINT @tsql 
     INSERT sync_createFK  
         (
         Script 
         ) 
         VALUES (
           @tsql 
           ) 

-------------------Generate CHECK CONSTRAINT scripts for a database ------------------------------ 
---------------------------------------------------------------------------------------------------------- 

     BEGIN 

     SET @tsql = 'ALTER TABLE ' 
        + QUOTENAME(@schema_name) 
        + '.' 
        + QUOTENAME(@table_name) 
        + 
         CASE @is_disabled 
          WHEN 0 THEN ' CHECK ' 
           ELSE ' NOCHECK ' 
         END 
        + 'CONSTRAINT ' 
        + QUOTENAME(@constraint_name) 
        + ';'; 
     --PRINT @tsql; 
     INSERT sync_createCHECK 
         (
         Script 
         ) 
         VALUES (
           @tsql 
           ) 
     END; 

    FETCH NEXT FROM FKcursor INTO 
    @schema_name 
    , @table_name 
    , @constraint_name 
    , @referenced_object_name 
    , @constraint_object_id 
    , @is_disabled 
    , @is_not_for_replication 
    , @is_not_trusted 
    , @delete_referential_action 
    , @update_referential_action 
    , @referenced_schema_name; 

END; 

CLOSE FKcursor; 

DEALLOCATE FKcursor; 

--SELECT * FROM sync_DropFK 
--SELECT * FROM sync_CreateFK 
--SELECT * FROM sync_CreateCHECK 
--------------------------------------------------------------------------- 
2.) 
----------------------------------------------------------------------------------------------------------------- 
----------------------------execute Drop FK Scripts -------------------------------------------------- 

DECLARE @scriptD NVARCHAR(4000) 

DECLARE DropFKCursor CURSOR FOR 
    SELECT Script 
    FROM sync_dropFK WITH (NOLOCK) 

OPEN DropFKCursor 

FETCH NEXT FROM DropFKCursor 
INTO @scriptD 

WHILE @@FETCH_STATUS = 0 
BEGIN 
--PRINT @scriptD 
EXEC (@scriptD) 
FETCH NEXT FROM DropFKCursor 
INTO @scriptD 
END 
CLOSE DropFKCursor 
DEALLOCATE DropFKCursor 
-------------------------------------------------------------------------------- 
3.) 

------------------------------------------------------------------------------------------------------------------ 
----------------------------Truncate all tables in the database other than our staging tables -------------------- 
------------------------------------------------------------------------------------------------------------------ 


EXEC sp_MSforeachtable 'IF OBJECT_ID(''?'') NOT IN 
(
ISNULL(OBJECT_ID(''dbo.sync_createCHECK''),0), 
ISNULL(OBJECT_ID(''dbo.sync_createFK''),0), 
ISNULL(OBJECT_ID(''dbo.sync_dropFK''),0) 
) 
BEGIN TRY 
TRUNCATE TABLE ? 
END TRY 
BEGIN CATCH 
PRINT ''Truncation failed on''+ ? +'' 
END CATCH;' 
GO 
------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------- 
----------------------------execute Create FK Scripts and CHECK CONSTRAINT Scripts--------------- 
----------------------------tack me at the end of the ETL in a SQL task------------------------- 
------------------------------------------------------------------------------------------------- 
DECLARE @scriptC NVARCHAR(4000) 

DECLARE CreateFKCursor CURSOR FOR 
    SELECT Script 
    FROM sync_createFK WITH (NOLOCK) 

OPEN CreateFKCursor 

FETCH NEXT FROM CreateFKCursor 
INTO @scriptC 

WHILE @@FETCH_STATUS = 0 
BEGIN 
--PRINT @scriptC 
EXEC (@scriptC) 
FETCH NEXT FROM CreateFKCursor 
INTO @scriptC 
END 
CLOSE CreateFKCursor 
DEALLOCATE CreateFKCursor 
------------------------------------------------------------------------------------------------- 
DECLARE @scriptCh NVARCHAR(4000) 

DECLARE CreateCHECKCursor CURSOR FOR 
    SELECT Script 
    FROM sync_createCHECK WITH (NOLOCK) 

OPEN CreateCHECKCursor 

FETCH NEXT FROM CreateCHECKCursor 
INTO @scriptCh 

WHILE @@FETCH_STATUS = 0 
BEGIN 
--PRINT @scriptCh 
EXEC (@scriptCh) 
FETCH NEXT FROM CreateCHECKCursor 
INTO @scriptCh 
END 
CLOSE CreateCHECKCursor 
DEALLOCATE CreateCHECKCursor 
5

WITH CHECK CHECK почти наверняка требуется!

Этот вопрос был поднят в некоторых ответах и ​​комментариях, но я чувствую, что это достаточно важно, чтобы снова вызвать его.

Повторное включение ограничения с использованием следующей команды (нет WITH CHECK) будет содержать serious drawbacks.

ALTER TABLE MyTable CHECK CONSTRAINT MyConstraint; 

обратными | С NOCHECK

Указывает, являются ли данные в таблице или не подтверждены с помощью недавно добавленного или повторно включенного ограничения FOREIGN KEY или CHECK. Если не указано , для новых ограничений предполагается WITH CHECK, а для возобновляемых ограничений используется NOKECK .

Если вы не хотите проверять новые ограничения CHECK или FOREIGN KEY против существующих данных, используйте WITH NOCHECK. Мы не рекомендуем делать , за исключением редких случаев. Новое ограничение будет оцениваться в все последующие обновления данных. Любые нарушения ограничений, которые подавляются с помощью NOCHECK при добавлении ограничения, могут привести к сбою будущих обновлений , если они обновляют строки данными, которые не соответствуют ограничению .

Оптимизатор запросов не учитывает ограничения, которые определены С NOCHECK. Такие ограничения игнорируются до тех пор, пока они не будут повторно активированы , используя таблицу ALTER TABLE WITH CHECK CHECK CONSTRAINT ALL.

Примечание: С NOCHECK по умолчанию для повторного включения ограничений. Я должен задаться вопросом, почему ...

  1. В ходе выполнения этой команды не будут оцениваться существующие данные в таблице - успешное завершение не гарантирует, что данные в таблице действительны в соответствии с ограничением.
  2. Во время следующего обновления недопустимых записей ограничение будет оцениваться и не будет выполнено, что приведет к ошибкам, которые могут быть не связаны с фактическим обновлением.
  3. Логика приложения, которая полагается на ограничение, чтобы гарантировать достоверность данных, может завершиться неудачей.
  4. Оптимизатор запросов не будет использовать какое-либо ограничение, которое будет включено таким образом.

Системный вид sys.foreign_keys обеспечивает определенную видимость проблемы. Обратите внимание, что он имеет как is_disabled, так и столбец is_not_trusted. is_disabled указывает, будут ли проверены будущие операции манипуляции данными с ограничением.is_not_trusted указывает, были ли все данные, находящиеся в настоящее время в таблице, проверены на ограничение.

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint; 

Есть ли у вас препятствия, которым нужно доверять? Узнать ...

SELECT * FROM sys.foreign_keys WHERE is_not_trusted = 1; 
0

У меня есть более полезная версия, если вы заинтересованы. Я снял здесь немного кода http://www.dbaservices.com.au/news/drop-recreate-foreign-key-constraints/, изменяя его, чтобы разрешить массив таблиц в хранимой процедуре, и он заполняет команды drop, truncate, add, перед выполнением всех из них. Это дает вам возможность решить, какие таблицы нужно усекать.

/****** Object: UserDefinedTableType [util].[typ_objects_for_managing] Script Date: 03/04/2016 16:42:55 ******/ 
CREATE TYPE [util].[typ_objects_for_managing] AS TABLE(
    [schema] [sysname] NOT NULL, 
    [object] [sysname] NOT NULL 
) 
GO 

create procedure [util].[truncate_table_with_constraints] 
@objects_for_managing util.typ_objects_for_managing readonly 

[email protected] sysname 
--,@table sysname 

as 
--select 
-- @table = 'TABLE', 
-- @schema = 'SCHEMA' 

declare @exec_table as table (ordinal int identity (1,1), statement nvarchar(4000), primary key (ordinal)); 

--print '/*Drop Foreign Key Statements for ['[email protected]+'].['[email protected]+']*/' 

insert into @exec_table (statement) 
select 
      'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+ o.name+'] DROP CONSTRAINT ['+fk.name+']' 
from sys.foreign_keys fk 
inner join sys.objects o 
      on fk.parent_object_id = o.object_id 
where 
exists ( 
select * from @objects_for_managing chk 
where 
chk.[schema] = SCHEMA_NAME(o.schema_id) 
and 
chk.[object] = o.name 
) 
; 
      --o.name = @table and 
      --SCHEMA_NAME(o.schema_id) = @schema 

insert into @exec_table (statement) 
select 
'TRUNCATE TABLE ' + src.[schema] + '.' + src.[object] 
from @objects_for_managing src 
; 

--print '/*Create Foreign Key Statements for ['[email protected]+'].['[email protected]+']*/' 
insert into @exec_table (statement) 
select 'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+o.name+'] ADD CONSTRAINT ['+fk.name+'] FOREIGN KEY (['+c.name+']) 
REFERENCES ['+SCHEMA_NAME(refob.schema_id)+'].['+refob.name+'](['+refcol.name+'])' 
from sys.foreign_key_columns fkc 
inner join sys.foreign_keys fk 
      on fkc.constraint_object_id = fk.object_id 
inner join sys.objects o 
      on fk.parent_object_id = o.object_id 
inner join sys.columns c 
      on  fkc.parent_column_id = c.column_id and 
        o.object_id = c.object_id 
inner join sys.objects refob 
      on fkc.referenced_object_id = refob.object_id 
inner join sys.columns refcol 
      on fkc.referenced_column_id = refcol.column_id and 
        fkc.referenced_object_id = refcol.object_id 
where 
exists ( 
select * from @objects_for_managing chk 
where 
chk.[schema] = SCHEMA_NAME(o.schema_id) 
and 
chk.[object] = o.name 
) 
; 

      --o.name = @table and 
      --SCHEMA_NAME(o.schema_id) = @schema 



declare @looper int , @total_records int, @sql_exec nvarchar(4000) 

select @looper = 1, @total_records = count(*) from @exec_table; 

while @looper <= @total_records 
begin 

select @sql_exec = (select statement from @exec_table where ordinal [email protected]) 
exec sp_executesql @sql_exec 
print @sql_exec 
set @looper = @looper + 1 
end 
1

правой кнопкой мыши дизайн таблицы и перейти к отношениям и выбрать внешний ключ на левой боковой панели и в правой боковой панели, установите Принудительно ограничение внешнего ключа «Да» (для включения внешнего ключа) или «Нет» (чтобы отключить его). enter image description here

0

Один сценария, чтобы управлять ими все: это сочетает в себе укоротить и удалять команды с sp_MSforeachtable, так что вы можете избежать падений и воссоздавать ограничения - просто указать таблицы, которые должны быть удалены, а не усеченной и для моих целей я включившие дополнительный фильтр схемы для хорошей меры (проверен в 2008R2)

declare @schema nvarchar(max) = 'and Schema_Id=Schema_id(''Value'')' 
declare @deletiontables nvarchar(max) = '(''TableA'',''TableB'')' 
declare @truncateclause nvarchar(max) = @schema + ' and o.Name not in ' + + @deletiontables; 
declare @deleteclause nvarchar(max) = @schema + ' and o.Name in ' + @deletiontables;   

exec sp_MSforeachtable 'alter table ? nocheck constraint all', @[email protected] 
exec sp_MSforeachtable 'truncate table ?', @[email protected] 
exec sp_MSforeachtable 'delete from ?', @[email protected] 
exec sp_MSforeachtable 'alter table ? with check check constraint all', @[email protected] 
0

Ответ пометка «905» выглядит хорошо, но не работает.

Следующие работали для меня. Любой основной ключ, уникальный ключ или ограничения по умолчанию CAN NOT отключить. Фактически, если «sp_helpconstraint» показывает «n/a» в status_enabled - означает, что он может быть включен/отключен NOT.

- Чтобы создать сценарий для DISABLE

select 'ALTER TABLE ' + object_name(id) + ' NOCHECK CONSTRAINT [' + object_name(constid) + ']' 
from sys.sysconstraints 
where status & 0x4813 = 0x813 order by object_name(id) 

- Для создания сценария ВКЛЮЧИТЬ

select 'ALTER TABLE ' + object_name(id) + ' CHECK CONSTRAINT [' + object_name(constid) + ']' 
from sys.sysconstraints 
where status & 0x4813 = 0x813 order by object_name(id) 
1

Вы на самом деле должны быть в состоянии отключить ограничения внешнего ключа так же, как временно отключить другие ограничения :

Alter table MyTable nocheck constraint FK_ForeignKeyConstraintName 

Просто убедитесь, что вы отключили ограничение на th e первая таблица, указанная в имени ограничения. Например, если мое ограничение внешнего ключа было FK_LocationsEmployeesLocationIdEmployeeId, я хотел бы использовать следующее:

Alter table Locations nocheck constraint FK_LocationsEmployeesLocationIdEmployeeId 

даже если нарушение этого ограничения будет выдавать ошибку, что не обязательно заявить, что в таблицу в качестве источника конфликта.

Смежные вопросы