ข้อ จำกัด foreign key สามารถปิดใช้งานชั่วคราวโดยใช้ T-SQL ได้อย่างไร


824

การปิดใช้งานและการเปิดใช้งานข้อ จำกัด คีย์ต่างประเทศรองรับใน SQL Server หรือไม่ หรือจะเป็นตัวเลือกเดียวของฉันไปdropแล้วอีกcreateข้อ จำกัด ?


128
สำหรับผู้ที่ถามว่า "ทำไม" ฉันต้องการทำสิ่งนี้: มันเป็นสภาพแวดล้อมการทดสอบที่ฉันต้องการที่จะลบและโหลดข้อมูลการทดสอบจากหลาย ๆ ตารางโดยไม่จำเป็นต้องบำรุงรักษาและระบุลำดับการโหลดข้อมูล ความถูกต้องของข้อมูลไม่สำคัญสำหรับสถานการณ์นี้
Ray

8
หมายเหตุ - หากคุณต้องการตัดทอนตารางคุณจะต้องยกเลิกข้อ จำกัด จริง ๆ
ดีเด่นเรียกเก็บเงิน

@OutstandingBill เห็นได้ชัดว่างานนี้ได้ตัด
jpaugh

1
ดูเหมือนว่าแปลกที่ทุกคนจะถามมันในสภาพแวดล้อมการผลิต กรณีการใช้งานทั่วไปสำหรับการแทรกจำนวนมาก หากคุณมีตารางอ้างอิงตนเองบางครั้งก็เป็นเรื่องยากอย่างยิ่งในการเรียงลำดับการแทรกจำนวนมากเพื่อให้แถวหลักถูกแทรกก่อนหน้าลูกเสมอดังนั้นคุณจึงปิดการใช้งานข้อ จำกัด การแทรกจำนวนมากเปิดใช้งานข้อ จำกัด
Auspex

คำตอบ:


1126

หากคุณต้องการปิดการใช้งานข้อ จำกัด ทั้งหมดในฐานข้อมูลเพียงแค่เรียกใช้รหัสนี้:

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

ฉันพบว่ามีประโยชน์เมื่อเติมข้อมูลจากฐานข้อมูลหนึ่งไปยังอีกฐานข้อมูลหนึ่ง มันเป็นวิธีที่ดีกว่าการวางข้อ จำกัด อย่างที่คุณพูดถึงมันมีประโยชน์เมื่อปล่อยข้อมูลทั้งหมดในฐานข้อมูลและ repopulating มัน (พูดในสภาพแวดล้อมการทดสอบ)

หากคุณกำลังลบข้อมูลทั้งหมดคุณอาจพบว่าวิธีนี้มีประโยชน์

นอกจากนี้บางครั้งก็เป็นประโยชน์ในการปิดการใช้งานทริกเกอร์ทั้งหมดรวมทั้งคุณสามารถดูโซลูชั่นที่สมบูรณ์ที่นี่


9
"ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"ควรมีเพียง "เช็ค" เดียวหรือไม่
CrazyPyro

27
@CrazyPyro - คุณไม่จำเป็นต้องใช้ทั้งคู่
kristof

32
@CrazyPyro: ทั้งสองมีความจำเป็นจริง ๆ เพราะนั่นเป็นเพราะการตรวจสอบครั้งแรกเป็นของ with และการตรวจสอบที่สองที่มีข้อ จำกัด (มันเป็นประเภทของข้อ จำกัด ) การตรวจสอบครั้งแรกทำให้มั่นใจได้ว่าข้อมูลของคุณได้รับการตรวจสอบความสอดคล้องเมื่อเปิดใช้งานข้อ จำกัด หากคุณไม่ต้องการสิ่งนั้นคุณสามารถเขียนด้วย NOCHECK มีประโยชน์ในบางสถานการณ์การทดสอบเมื่อคุณไม่สนใจข้อมูลจริงตราบใดที่มีบางอย่างเพื่อให้คิวรีของคุณมีข้อมูลที่จะเล่น
Valentino Vranken

8
มันแย่ไหมที่ฉันได้ผลลัพธ์นี้ในคำสั่งที่สอง? "คำสั่งเปลี่ยนแปลงตารางขัดแย้งกับข้อ จำกัด ของคีย์ต่างประเทศ ... "
ผู้สนับสนุนของปีศาจ

34
เป็นที่น่าสังเกตว่าแม้เมื่อปิดการใช้งานข้อ จำกัด TRUNCATE TABLE จะไม่ทำงาน เพื่อที่คุณจะต้องวางข้อ จำกัด มิฉะนั้นการใช้ DELETE FROM แต่ต้องคำนึงถึงความแตกต่าง: mssqltips.com/sqlservertip/1080/...
เจมส์ McCormack

404

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

29
การค้นหาที่ดี แต่โปรดทราบว่าคุณยังไม่สามารถตัดทอนตารางโดยไม่ลบข้อ จำกัด รหัสต่างประเทศได้
Steven A. Lowe

1
และคุณจะต้องระวังด้วยว่าเมื่อคุณเปิดข้อ จำกัด อีกครั้งและทำการตรวจสอบความสมบูรณ์ของข้อมูลข้อมูลของคุณอาจล้มเหลวและแก้ไขปัญหาเช่นนั้นอาจเป็นฝันร้ายหากข้อมูลที่ล้มเหลวอยู่ท้ายสตริงที่ยาวของ ข้อ จำกัด ที่เชื่อมโยง
Jimoc

1
คุณต้องตรวจสอบอีกครั้งเมื่อเปิดข้อ จำกัด อีกครั้ง มิฉะนั้นรหัสของคุณจะตรวจสอบข้อ จำกัด เพียงครั้งเดียวเท่านั้นไม่เปิดใช้งาน
ps2goat

3
ใช่ "ด้วยเครื่องหมายถูกเช็ค" จำเป็นสำหรับปี 2012 การแก้ไขถูกปฏิเสธใช่ไหม MS Link
crokusek

1
คำสั่งที่ใช้ที่นี่เพื่อเปิดใช้งานข้อ จำกัด จะหายไปกับคำสั่ง WITH CHECK นี่คือข้อบกพร่องที่สำคัญสวย ดูคำตอบของฉันสำหรับรายละเอียด - stackoverflow.com/a/35427150/81595
Scott Munro

37

เพื่อปิดการใช้งานข้อ จำกัด คุณมีALTERตารางโดยใช้NOCHECK

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

เพื่อให้คุณต้องใช้การตรวจสอบสองครั้ง:

ALTER TABLE [TABLE_NAME] WITH CHECK CHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
  • ให้ความสนใจกับการตรวจสอบสองครั้งเมื่อเปิดใช้งาน
  • ALL หมายถึงข้อ จำกัด ทั้งหมดในตาราง

เมื่อเสร็จแล้วหากคุณต้องการตรวจสอบสถานะให้ใช้สคริปต์นี้เพื่อแสดงรายการข้อ จำกัด จะเป็นประโยชน์อย่างมาก:

    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 

ไม่ได้ดูสำหรับคีย์หลัก ? สำหรับคีย์ต่างประเทศ SYSFOREIGNKEYS มุมมองระบบ sys.sysforeignkeys msdn.microsoft.com/en-us/library/ms177604.aspx
Kiquenet

หากคุณพยายามปิดการใช้งานคีย์หลักสำหรับการแทรกฉันจะขอแนะนำให้ใช้ (SET IDENTITY_INSERT) หากคุณต้องการเพียงตรวจสอบคีย์หลักคุณสามารถลอง sys.key_constraints ด้วย sys.indexes.is_primary_key
Diego Mendes

29

ตัวเลือกที่ดีที่สุดของคุณคือ DROP และสร้างข้อ จำกัด คีย์ต่างประเทศ

ฉันไม่พบตัวอย่างในโพสต์นี้ที่จะทำงานสำหรับฉัน "ตาม - เป็น" อย่างใดอย่างหนึ่งจะไม่ทำงานถ้าคีย์ต่างประเทศอ้างอิง schema ที่แตกต่างกันอื่น ๆ จะไม่ทำงานถ้าคีย์ต่างประเทศอ้างอิงหลายคอลัมน์ สคริปต์นี้พิจารณาทั้ง schema หลายรายการและหลายคอลัมน์ต่อคีย์ต่างประเทศ

นี่คือสคริปต์ที่สร้างคำสั่ง "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
คุณสามารถอธิบายได้หรือไม่ว่าทำไมถึงดีกว่าการปิดใช้งานและเปิดใช้งานข้อ จำกัด อีกครั้ง
Mahmoodvcs

สคริปต์ที่ดี สำหรับวิธีการที่คล้ายกัน แต่เป็นทางเลือกดูที่: mssqltips.com/sqlservertip/3347/…
Matt Browne

11

มาตรฐาน SQL-92 อนุญาตให้มีการประกาศค่าคงที่เป็น DEFERRABLE เพื่อให้สามารถเลื่อนได้ (โดยนัยหรือโดยชัดแจ้ง) ภายในขอบเขตของธุรกรรม น่าเศร้าที่ SQL Server ยังขาดฟังก์ชันการทำงานของ SQL-92 นี้

สำหรับฉันการเปลี่ยนข้อ จำกัด เป็น NOCHECK นั้นคล้ายกับการเปลี่ยนโครงสร้างฐานข้อมูลบนข้อ จำกัด การลดลงอย่างแน่นอนคือ - และสิ่งที่ต้องหลีกเลี่ยง (เช่นผู้ใช้ต้องการสิทธิ์ที่เพิ่มขึ้น)


11
   --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 หรือเมื่อต้องการทำซ้ำข้อมูลดูเหมือนว่าจำเป็นต้องปิดหรือวางข้อ จำกัด คีย์ต่างประเทศชั่วคราวจากนั้นเปิดใช้งานหรือสร้างใหม่อีกครั้ง ในกรณีเหล่านี้ Referential Integrity ไม่ได้เป็นปัญหาเพราะมันถูกเก็บรักษาไว้ในฐานข้อมูลแหล่งที่มา ดังนั้นคุณสามารถมั่นใจได้ในเรื่องนี้


สคริปต์นี้ยอดเยี่ยมสำหรับการสร้างคำสั่ง "ALTER" ของฉัน แต่ฉันจะได้รับสิ่งเหล่านี้เพื่อรัน / รันใน SP ได้อย่างไร
BlueChippy

1
ฉันคิดว่ามันจะไม่ทำงานหากคีย์ต่างประเทศใด ๆ เป็นแบบหลายคอลัมน์
Zar Shardan

สิ่งนี้ไม่ได้ผลิตอักขระทั้งหมดสำหรับชื่อตาราง / คีย์ที่ยาวเกินไป
Joshua Drake

11
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

10

WITH CHECK CHECK จำเป็นต้องมีเกือบแน่นอน!

ประเด็นนี้เกิดขึ้นจากคำตอบและความคิดเห็นบางส่วน แต่ฉันรู้สึกว่ามันสำคัญพอที่จะเรียกมันออกมาอีกครั้ง

เปิดใช้งานข้อ จำกัด การใช้คำสั่งดังต่อไปนี้ (ไม่WITH CHECK) จะมีบางข้อบกพร่องร้ายแรง

ALTER TABLE MyTable CHECK CONSTRAINT MyConstraint;

ด้วยการตรวจสอบ ด้วย NOCHECK

ระบุว่าข้อมูลในตารางเป็นหรือไม่ได้รับการตรวจสอบความถูกต้องกับข้อ จำกัด ที่เพิ่มเข้ามาใหม่หรือเปิดใช้งานอีกครั้งหรือตรวจสอบ CHECK หากไม่ได้ระบุไว้จะมีการพิจารณาด้วย CHECK สำหรับข้อ จำกัด ใหม่และจะมีการสันนิษฐานด้วย WITH NOCHECK สำหรับข้อ จำกัด ที่เปิดใช้งานอีกครั้ง

หากคุณไม่ต้องการยืนยันข้อ จำกัด CHECK หรือ FOREIGN KEY ใหม่กับข้อมูลที่มีอยู่ให้ใช้ WITH NOCHECK เราไม่แนะนำให้ทำเช่นนี้ยกเว้นในบางกรณี ข้อ จำกัด ใหม่จะถูกประเมินในการอัพเดทข้อมูลในภายหลังทั้งหมด การละเมิดข้อ จำกัด ใด ๆ ที่ถูกระงับด้วย WITH NOCHECK เมื่อมีการเพิ่มข้อ จำกัด อาจทำให้การอัปเดตในอนาคตล้มเหลวหากพวกเขาอัปเดตแถวด้วยข้อมูลที่ไม่สอดคล้องกับข้อ จำกัด

เครื่องมือเพิ่มประสิทธิภาพการสืบค้นไม่พิจารณาข้อ จำกัด ที่กำหนดไว้ด้วย NOCHECK ข้อ จำกัด ดังกล่าวจะถูกละเว้นจนกว่าจะเปิดใช้งานอีกครั้งโดยใช้ตาราง ALTER TABLE พร้อม 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;

9

โพสต์แรก :)

สำหรับ OP โซลูชันของ kristof จะทำงานได้เว้นแต่จะมีปัญหาเกี่ยวกับข้อมูลจำนวนมากและปัญหาบอลลูนบันทึกธุรกรรมในการลบขนาดใหญ่ นอกจากนี้แม้จะมีหน่วยเก็บข้อมูล tlog เป็นอะไหล่เนื่องจากลบเขียนไปยังบล็อกซึ่งเป็นการดำเนินการอาจใช้เวลานานมากสำหรับตารางที่มีหลายร้อยล้านแถว

ฉันใช้เคอร์เซอร์จำนวนหนึ่งเพื่อตัดและโหลดสำเนาจำนวนมากของหนึ่งในฐานข้อมูลการผลิตขนาดใหญ่ของเราบ่อยครั้ง วิธีการแก้ปัญหาที่ออกแบบมาสำหรับบัญชีหลาย schemas, คอลัมน์สำคัญต่างประเทศและที่ดีที่สุดของทั้งหมดสามารถ sproc'd ออกมาเพื่อใช้ใน SSIS

มันเกี่ยวข้องกับการสร้างตาราง staging สามตาราง (ตารางจริง) เพื่อจัดวางสคริปต์ DROP, CREATE และ CHECK FK การสร้างและการแทรกสคริปต์เหล่านั้นลงในตารางจากนั้นวนรอบตารางและเรียกใช้งานตารางเหล่านั้น สคริปต์ที่แนบมามีสี่ส่วน: 1. ) การสร้างและจัดเก็บสคริปต์ในตารางสามขั้นตอน (จริง), 2) การดำเนินการของสคริปต์ FK แบบดรอปดาวน์ผ่านเคอร์เซอร์หนึ่งต่อหนึ่ง, 3) การใช้ sp_MSforeachtable เพื่อตัดทอนทั้งหมด ตารางในฐานข้อมูลอื่นนอกเหนือจากตาราง staging สามและ 4) การดำเนินการสร้าง FK และตรวจสอบสคริปต์ FK ที่ส่วนท้ายของแพ็คเกจ ETL SSIS ของคุณ

รันส่วนการสร้างสคริปต์ในงาน Execute SQL ใน SSIS เรียกใช้ส่วน "ดำเนินการปล่อยสคริปต์ FK" ในงาน Execute SQL ที่สอง วางสคริปต์การตัดปลายในงาน Execute SQL ที่สามจากนั้นดำเนินการกระบวนการ 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

7

ค้นหาข้อ จำกัด

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

เซฟเวย์

หมายเหตุ: เพิ่มโซลูชันสำหรับการปล่อยข้อ จำกัด เพื่อให้ตารางสามารถถูกดร็อปหรือแก้ไขได้โดยไม่มีข้อผิดพลาดใด ๆ


3

คลิกขวาที่การออกแบบตารางและไปที่ความสัมพันธ์และเลือกคีย์ต่างประเทศในบานหน้าต่างด้านซ้ายและในบานหน้าต่างด้านขวาตั้งค่าบังคับใช้ข้อ จำกัด คีย์ต่างประเทศเป็น 'ใช่' (เพื่อเปิดใช้งานข้อ จำกัด คีย์ต่างประเทศ) หรือ 'ไม่' ( ปิดการใช้งาน) ป้อนคำอธิบายรูปภาพที่นี่


3

คำตอบที่มีเครื่องหมาย '905' ดูดี แต่ใช้งานไม่ได้

ทำงานต่อไปนี้สำหรับฉัน คีย์หลักคีย์ที่ไม่ซ้ำหรือข้อ จำกัด เริ่มต้นไม่สามารถปิดใช้งานได้ ในความเป็นจริงถ้า 'sp_helpconstraint' 'แสดง' n / a 'ใน 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)

3

จริง ๆ แล้วคุณควรจะสามารถปิดการใช้งานข้อ จำกัด กุญแจต่างประเทศในลักษณะเดียวกับที่คุณปิดการใช้งานข้อ จำกัด ชั่วคราว:

Alter table MyTable nocheck constraint FK_ForeignKeyConstraintName

เพียงให้แน่ใจว่าคุณปิดการใช้งานข้อ จำกัด ในตารางแรกที่ระบุไว้ในชื่อข้อ จำกัด ตัวอย่างเช่นหากข้อ จำกัด กุญแจสำคัญในต่างประเทศของฉันคือ FK_LocationsEmployeesLocationIdEmployeeId ฉันจะต้องการใช้สิ่งต่อไปนี้:

Alter table Locations nocheck constraint FK_LocationsEmployeesLocationIdEmployeeId

แม้ว่าการละเมิดข้อ จำกัด นี้จะสร้างข้อผิดพลาดที่ไม่จำเป็นต้องระบุว่าตารางนั้นเป็นแหล่งที่มาของความขัดแย้ง


1

หนึ่งสคริปต์สำหรับกฎทั้งหมด: รวมคำสั่ง truncate และ delete ด้วย 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

1

คุณสามารถปิดการใช้งานข้อ จำกัด ชั่วคราวบนโต๊ะทำงานจากนั้นสร้างใหม่

นี่เป็นวิธีง่ายๆในการทำ ...

ปิดการใช้งานดัชนีทั้งหมดรวมถึงคีย์หลักซึ่งจะปิดใช้งานคีย์ต่างประเทศทั้งหมดจากนั้นเปิดใช้งานคีย์หลักอีกครั้งเพื่อให้คุณสามารถทำงานกับ ...

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

สิ่งนี้ดูมีแนวโน้ม แต่@sqlจะถูกตัดทอนเสมอ :(
Will Strohl

1

ฉันมีรุ่นที่มีประโยชน์มากกว่านี้ถ้าคุณสนใจ ฉันยกโค้ดเล็กน้อยจากที่นี่เป็นเว็บไซต์ที่ลิงก์ไม่ทำงานอีกต่อไป ฉันแก้ไขมันเพื่ออนุญาตให้อาเรย์ของตารางในโพรซีเดอร์ที่เก็บไว้และมันเติมการดร็อปตัดทอนเพิ่มคำสั่งก่อนที่จะดำเนินการทั้งหมด สิ่งนี้ช่วยให้คุณสามารถควบคุมการตัดสินใจว่าตารางใดที่ต้องตัดทอน

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

ลิงก์ตายในคำตอบของคุณ จุดบทความว่างเปล่า
Neolisk

สวัสดีอาจมี deadlink อยู่ แต่รหัสทั้งหมดจะถูกระบุในส่วน เกิดอะไรขึ้นกับสิ่งนี้?
Zak Willis

ไม่มีอะไรผิดปกติ แต่คุณควรแก้ไขคำตอบและลบลิงก์ที่ไม่ทำงานออก
Neolisk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.