كيف يمكن تعطيل قيود المفاتيح الخارجية مؤقتًا باستخدام T-SQL؟

StackOverflow https://stackoverflow.com/questions/159038

سؤال

هل يتم دعم تعطيل وتمكين قيود المفاتيح الخارجية في SQL Server؟أم أن خياري الوحيد هو ذلك drop وثم يكرر-create القيود؟

هل كانت مفيدة؟

المحلول

إذا كنت ترغب في تعطيل كافة القيود في قاعدة البيانات فقط تشغيل هذا الرمز:

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

وأجد أنه من المفيد عند ملء البيانات من قاعدة بيانات واحدة إلى أخرى. ومن نهج أفضل بكثير من القيود إسقاط. كما ذكرت أنها تأتي في متناول يدي عندما يسقط كافة البيانات في قاعدة البيانات وإعادة إسكانها (ويقول في بيئة اختبار).

إذا كنت تقوم بحذف جميع البيانات التي قد تجد <لأ href = "https://stackoverflow.com/questions/155246/how-do-you-truncate-all-tables-in-a-database-using- TSQL # 156813 "> هذا الحل لتكون مفيدة.

وأيضا في بعض الأحيان هو مفيد لتعطيل كافة يطلق كذلك، يمكنك ان ترى حلا كاملا <لأ href = "https://stackoverflow.com/questions/123558/sql-server-2005-t-sql-to- بشكل مؤقت تعطيل واحد في الزناد # 123966 "> هنا .

نصائح أخرى

http://www.sqljunkies.com/ سجل الويب / الرومانية / أرشيف / 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

إلى تعطيل القيد يجب تغيير الجدول باستخدام NOCHECK

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

لتمكين لديك لاستخدام مزدوج تحقق

ALTER TABLE [TABLE_NAME] WITH CHECK CHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
  • إيلاء الاهتمام مزدوجة تحقق الاختيار عند تمكين.
  • بكل الوسائل عن كل القيود في الجدول.

الانتهاء مرة واحدة ، إذا كنت تحتاج إلى التحقق من حالة استخدام هذا البرنامج النصي إلى قائمة القيد الوضع.سيكون مفيدا جدا:

    SELECT (CASE 
        WHEN OBJECTPROPERTY(CONSTID, 'CNSTISDISABLED') = 0 THEN 'ENABLED'
        ELSE 'DISABLED'
        END) AS STATUS,
        OBJECT_NAME(CONSTID) AS CONSTRAINT_NAME,
        OBJECT_NAME(FKEYID) AS TABLE_NAME,
        COL_NAME(FKEYID, FKEY) AS COLUMN_NAME,
        OBJECT_NAME(RKEYID) AS REFERENCED_TABLE_NAME,
        COL_NAME(RKEYID, RKEY) AS REFERENCED_COLUMN_NAME
   FROM SYSFOREIGNKEYS
ORDER BY TABLE_NAME, CONSTRAINT_NAME,REFERENCED_TABLE_NAME, KEYNO 

أفضل خيار لديك هو إسقاط وإنشاء قيود المفتاح الخارجي.

لم أجد أمثلة في هذا المنشور من شأنها أن تعمل بالنسبة لي "كما هي"، ولن يعمل أحدهما إذا كانت المفاتيح الخارجية تشير إلى مخططات مختلفة، ولن يعمل الآخر إذا كان المفتاح الخارجي يشير إلى أعمدة متعددة.يأخذ هذا البرنامج النصي في الاعتبار كلا من المخططات المتعددة والأعمدة المتعددة لكل مفتاح خارجي.

فيما يلي البرنامج النصي الذي يقوم بإنشاء عبارات "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

والمعيار SQL-92 يسمح لconstaint أن أعلنت أنها DEFERRABLE بحيث يمكن تأجيلها (ضمنا أو صراحة) في نطاق معاملة. للأسف، SQL Server هو ما زالوا مفقودين هذه الوظيفة SQL-92.

وبالنسبة لي، تغيير القيد إلى NOCHECK هو أقرب إلى تغيير بنية قاعدة البيانات على الطاير - إسقاط القيود بالتأكيد هو - وهذا شيء يجب تجنبها (مثل المستخدمين تتطلب امتيازات زاد)

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

وأنا لا أتفق معك، هاملين. عندما كنت نقل البيانات باستخدام جهاز مباحث أمن الدولة أو عندما تريد تكرار البيانات، يبدو من الضروري جدا لتعطيل مؤقتا أو إسقاط قيود المفاتيح الخارجية ومن ثم إعادة تمكين أو إعادة إنتاجها. في هذه الحالات، التكامل المرجعي ليست قضية، لأنه يحتفظ بالفعل في قاعدة البيانات المصدر. لذلك، يمكنك أن تطمئن بشأن هذه المسألة.

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

وأول وظيفة:)

لوOP، والحل كريستوف في العمل، ما لم تكن هناك مشاكل مع البيانات الضخمة وقضايا سجل المعاملات بالون على حذف كبيرة. أيضا، حتى مع تخزين tlog لتجنيب، منذ حذف الكتابة إلى tlog، وهذه العملية يمكن أن تستغرق وقتا طويلا جدا للجداول مع مئات الملايين من الصفوف.

وأنا استخدم سلسلة من المؤشرات لاقتطاع وإعادة تحميل نسخ كبيرة من واحدة من قواعد بيانات الإنتاج ضخمة لدينا في كثير من الأحيان. حسابات حل هندسيا لمخططات متعددة، متعددة الأعمدة الرئيسية الخارجية، وأفضل للجميع يمكن sproc'd من أجل استخدامها في جهاز مباحث أمن الدولة.

وأنها تنطوي على إنشاء ثلاث تنظيم الجداول (الجداول الحقيقية) لإيواء DROP، وخلق، والتحقق من FK البرامج النصية، إنشاء وإدراج هذه النصوص في الجداول، ثم حلقات خلال الجداول وتنفيذها. البرنامج النصي المرفق هو أربعة أجزاء: 1.) إنشاء وتخزين البرامج النصية في تنظيم) طاولات حقيقية الثلاثة (2.) تنفيذ البرامج النصية انخفاض FK عن طريق المؤشر واحدا تلو الآخر، 3.) باستخدام sp_MSforeachtable لاقتطاع جميع الجداول في قاعدة البيانات الأخرى من لدينا ثلاثة جداول تنظيم و4.) تنفيذ إنشاء FK وتحقق من الكتابات FK في نهاية حزمة SSIS ETL الخاص بك.

وتشغيل جزء خلق النصي في مهمة تنفيذ SQL في جهاز مباحث أمن الدولة. تشغيل الجزء "تنفيذ البرامج النصية قطرة FK" في مهمة SQL الثانية تنفيذ. وضع السيناريو اقتطاع في مهمة تنفيذ SQL الثالثة، ثم نفذ أيا العمليات ETL الأخرى ما عليك القيام به قبل ربط إيجاد والتحقق البرامج النصية في مهمة تنفيذ SQL النهائية (أو اثنين إذا رغبت في ذلك) في نهاية تدفق التحكم الخاصة بك.

لقد ثبت تخزين البرامج النصية في جداول حقيقية لا تقدر بثمن عندما فشل إعادة تطبيق من المفاتيح الخارجية كما يمكنك تحديد * من sync_CreateFK، نسخ / لصق في إطار الاستعلام الخاص بك، تشغيلها في وقت واحد، وتحديد البيانات قضايا وعندما تجد تلك التي فشلت / لا تزال لا إعادة تطبيق.

ولا إعادة تشغيل البرنامج النصي مرة أخرى إذا فشلت دون التأكد من أن إعادة تطبيق كافة المفاتيح / الشيكات الخارجية قبل القيام بذلك، أو هل من المرجح أن تفقد بعض الخلق وتحقق كيه البرمجة كما تنظيم الجداول لدينا تم إسقاطها وإعادة إنشائها قبل إنشاء البرامج النصية لتنفيذه.

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

WITH CHECK CHECK يكاد يكون من المؤكد مطلوب!

لقد أثيرت هذه النقطة في بعض الإجابات والتعليقات ولكني أشعر أنه من المهم أن نذكرها مرة أخرى.

إعادة تمكين القيد باستخدام الأمر التالي (لا WITH CHECK) سيكون لها بعض عيوب خطيرة.

ALTER TABLE MyTable CHECK CONSTRAINT MyConstraint;

مع الشيك | مع Nocheck

يحدد ما إذا كانت البيانات الموجودة في الجدول أو لم يتم التحقق منها مقابل مفتاح خارجي مضاف حديثًا أو إعادة تمكينه حديثًا.إذا لم يتم تحديدها ، مع افتراض الشيك لقيود جديدة ، ومن المفترض أن يكون NoCheck لقيود إعادة تمكين.

إذا كنت لا ترغب في التحقق من قيود فحص جديدة أو قيود المفاتيح الخارجية مقابل البيانات الحالية ، فاستخدم مع NoCheck.لا نوصي بذلك ، إلا في حالات نادرة.سيتم تقييم القيد الجديد في جميع تحديثات البيانات اللاحقة.قد تتسبب أي انتهاكات للقيود التي يتم قمعها مع NOCHECK عند إضافة القيد إلى فشل التحديثات المستقبلية إذا قامت بتحديث الصفوف بالبيانات التي لا تتوافق مع القيد.

لا يعتبر محسن الاستعلام قيودًا محددة مع NoCheck.يتم تجاهل مثل هذه القيود حتى يتم إعادة تمكينها باستخدام جدول ALTER مع قيود التحقق من كل شيء.

ملحوظة: مع 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;

العثور على القيد

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

السيفوي.

ملاحظة:وأضاف حل droping القيد بحيث الجدول يمكن إسقاطها أو تعديلها دون أي قيود خطأ.

وانقر على الحق في تصميم الجدول والذهاب إلى العلاقات واختيار المفتاح الخارجي على جزء الجانب الأيسر وفي جزء الجانب الأيمن، تعيين فرض قيد مفتاح خارجي إلى "نعم" (تمكين قيود المفاتيح الخارجية) أو 'لا يوجد "(لتعطيله).

الجواب ملحوظ '905' تبدو جيدة ولكن لا يعمل.

التالية عملت بالنسبة لي.أي مفتاح أساسي, فريدة من نوعها الرئيسية أو الافتراضية القيود لا يمكن أن يتم تعطيل.في الواقع ، إذا كان 'sp_helpconstraint" يظهر "غير متاح" في status_enabled - يعني أنه يمكن أن لا تمكين/تعطيل.

-- لتوليد النصي إلى تعطيل

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)

ويجب أن تكون فعلا قادرة على تعطيل قيود المفاتيح الخارجية بنفس الطريقة التي تعطيل قيود أخرى مؤقتا:

Alter table MyTable nocheck constraint FK_ForeignKeyConstraintName

وفقط للتأكد من أنك تعطيل القيد في الجدول الأول المدرجة في اسم القيد. على سبيل المثال، إذا كان لي قيد مفتاح خارجي FK_LocationsEmployeesLocationIdEmployeeId، أريد أن استخدم ما يلي:

Alter table Locations nocheck constraint FK_LocationsEmployeesLocationIdEmployeeId

وعلى الرغم من انتهاك هذا القيد سوف ينتج خطأ لا بالضرورة القول بأن الجدول كمصدر للصراع.

واحد النصي لحكم كل منهم: هذا يجمع اقتطاع وحذف الأوامر مع 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', @whereand=@schema
exec sp_MSforeachtable 'truncate table ?', @whereand=@truncateclause
exec sp_MSforeachtable 'delete from ?', @whereand=@deleteclause
exec sp_MSforeachtable 'alter table ? with check check constraint all', @whereand=@schema

ويمكنك تعطيل القيود مؤقتا على الجداول الخاصة بك، لا عمل، ثم إعادة بنائها.

وهنا هو وسيلة سهلة لتحقيق ذلك ...

وتعطيل كافة الأرقام القياسية، بما في ذلك المفاتيح الأساسية، التي سيتم تعطيل كافة المفاتيح الخارجية، ثم إعادة تمكين مجرد المفاتيح الأساسية حتى تتمكن من العمل معهم ...

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON [' + t.[name] + '] DISABLE;'+CHAR(13)
from  
    sys.tables t
where type='u'

select @sql = @sql +
    'ALTER INDEX ' + i.[name] + ' ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.key_constraints i
join
    sys.tables t on i.parent_object_id=t.object_id
where
    i.type='PK'


exec dbo.sp_executesql @sql;
go

[نفعل شيئا، مثل تحميل البيانات]

وثم إعادة تمكين وإعادة بناء الفهارس ...

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.tables t
where type='u'

exec dbo.sp_executesql @sql;
go

ولدي نسخة أكثر فائدة إذا كنت مهتما. أنا رفعت قليلا من التعليمات البرمجية من هنا موقع على شبكة الانترنت حيث الارتباط لم تعد نشطة. I modifyied للسماح لمجموعة من الجداول في الإجراء المخزن وذلك بملء هذا التراجع، اقتطاع، إضافة البيانات قبل تنفيذ كل منهم. هذا يمنحك السيطرة لتحديد الجداول التي تحتاج اقتطاع.

/****** 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

--@schema 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 ['+@schema+'].['+@table+']*/'

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 ['+@schema+'].['+@table+']*/'
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 =@looper)
exec sp_executesql @sql_exec 
print @sql_exec 
set @looper = @looper + 1
end
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top