ไม่สามารถตัดทอนตารางได้เนื่องจากมีการอ้างอิงโดยข้อ จำกัด ของคีย์ต่างประเทศหรือไม่


459

การใช้ MSSQL2005 ฉันสามารถตัดทอนตารางด้วยข้อ จำกัด foreign key ได้หรือไม่ถ้าฉันตัดทอนตารางลูก (ตารางที่มีคีย์หลักของความสัมพันธ์ FK) เป็นอันดับแรก

ฉันรู้ว่าฉันสามารถ

  • ใช้DELETEคำสั่งที่ไม่มีตำแหน่งและจากนั้นจึงRESEEDระบุตัวตน
  • ลบ FK ตัดทอนตารางและสร้าง FK ใหม่

ฉันคิดว่าตราบใดที่ฉันตัดทอนตารางลูกต่อหน้าพ่อแม่ฉันก็โอเคโดยไม่ทำตามตัวเลือกข้างต้น แต่ฉันได้รับข้อผิดพลาดนี้:

ไม่สามารถตัดทอนตาราง 'TableName' ได้เนื่องจากกำลังถูกอ้างถึงโดยข้อ จำกัด ของ FOREIGN KEY

คำตอบ:


379

แก้ไข; คุณไม่สามารถตัดทอนตารางที่มีข้อ จำกัด FK ได้

โดยทั่วไปกระบวนการของฉันสำหรับสิ่งนี้คือ:

  1. ปล่อยข้อ จำกัด
  2. ตัดทอนตาราง
  3. สร้างข้อ จำกัด ใหม่

(ทั้งหมดในการทำธุรกรรมแน่นอน)

แน่นอนว่าสิ่งนี้ใช้ได้เฉพาะในกรณีที่เด็กถูกตัดทอนไปแล้วเท่านั้น ไม่เช่นนั้นฉันจะไปเส้นทางอื่นขึ้นอยู่กับว่าข้อมูลของฉันเป็นอย่างไร (มีตัวแปรมากเกินไปที่จะเข้าไปที่นี่)

โปสเตอร์ต้นฉบับพิจารณาแล้วว่าเป็นเช่นไร ดูคำตอบนี้สำหรับรายละเอียดเพิ่มเติม


73
"DELETE FROM" ไม่ได้รีเซ็ตคอลัมน์ที่เพิ่มขึ้นอัตโนมัติ การตัดทอน มันไม่สามารถใช้งานได้เทียบเท่า
robross0606

35
การตัดทอนมักเป็นสิ่งที่คุณต้องการทำหากคุณลบข้อมูลจำนวนมาก ตัดทอนล้านแถวหรือไม่ พันล้าน 1 ms ... ดังนั้น @ M07 โปรดอย่าพูดว่า "ลบจากวิธีการนั้นสะอาดกว่า" เพราะนั่นไม่ถูกต้องจากระยะไกล
ctb

1
หลังจากลบข้อมูลขนาดใหญ่ผู้ใช้จะต้องลดขนาดตารางและไฟล์บันทึกเพื่อเรียกคืนพื้นที่ดิสก์
Muhammad Yousaf Sulahria

2
ไม่แนะนำให้ใช้ปุ่ม Magic Shrink (หรือสคริปต์) 99% ของเวลา
Tom Stickel

1
แล้วคุณจะทำอย่างไร ตัวอย่างคำขอ
jeromej

356
DELETE FROM TABLENAME
DBCC CHECKIDENT ('DATABASENAME.dbo.TABLENAME',RESEED, 0)

โปรดทราบว่านี่อาจไม่ใช่สิ่งที่คุณต้องการหากคุณมีบันทึกนับล้านรายการเนื่องจากมันช้ามาก


นั่นเป็นวิธีที่มีประโยชน์และเร็วกว่าการปิดใช้งานและเปิดใช้งานข้อ จำกัด
อาจารย์

สิ่งนี้จะทำงานกับตารางที่มีข้อมูลน้อยกว่าเท่านั้น เห็นด้วยกับ @Pure
Dhanuka777

1
นี่เป็นสิ่งที่ดีสำหรับเมื่อคุณทดสอบสคีมาแล้ว
ohmusama

3
ฉันจะไม่แนะนำให้ไปเส้นทางนี้เนื่องจากคุณอาจได้รับข้อผิดพลาดนี้: คำสั่ง DELETE ที่ขัดแย้งกับข้อ จำกัด การอ้างอิง
sksallaj

ไม่ได้ผลสำหรับฉัน ยังคงได้รับข้อความ DELETE ที่ขัดแย้งกับข้อ จำกัด การอ้างอิง
emirhosseini

192

เนื่องจากTRUNCATE TABLEเป็นคำสั่ง DDLจึงไม่สามารถตรวจสอบเพื่อดูว่าระเบียนในตารางถูกอ้างอิงโดยบันทึกในตารางลูกหรือไม่

นี่คือสาเหตุที่ใช้DELETEงานได้และTRUNCATE TABLEไม่: เนื่องจากฐานข้อมูลสามารถตรวจสอบให้แน่ใจว่าไม่มีการอ้างอิงโดยระเบียนอื่น


92

ไม่มี ALTER TABLE

-- Delete all records
DELETE FROM [TableName]
-- Set current ID to "1"
-- If table already contains data, use "0"
-- If table is empty and never insert data, use "1"
-- Use SP https://github.com/reduardo7/TableTruncate
DBCC CHECKIDENT ([TableName], RESEED, 0)

เป็นขั้นตอนการจัดเก็บ

https://github.com/reduardo7/TableTruncate

โปรดทราบว่านี่อาจไม่ใช่สิ่งที่คุณต้องการหากคุณมีบันทึกนับล้านรายการเนื่องจากมันช้ามาก


3
การใช้ reseed new value = 1 หลังจาก DELETE FROM จะเริ่มต้นทั้งหมดจาก ID 2 แทนที่จะเป็น 1 จาก Technet ( technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx ) หากไม่มีแถวใด ๆ แทรกลงในตารางตั้งแต่สร้างหรือลบแถวทั้งหมดโดยใช้คำสั่ง TRUNCATE TABLE แถวแรกที่แทรกหลังจากที่คุณเรียกใช้ DBCC CHECKIDENT จะใช้ new_reseed_value เป็นข้อมูลประจำตัว มิฉะนั้นการแทรกแถวถัดไปจะใช้ new_reseed_value + ค่าการเพิ่มปัจจุบัน
Zoran P.

@ZoranP โปรดดูตัวแปรกระบวนงานที่เก็บไว้: github.com/reduardo7/TableTruncate
Eduardo Cuomo

4
CHECKIDENT DBCC ([TableName] RESEED, 0) ไม่ใช่ 1
Tico Fortes

1
@TicoFortes โพสต์อัปเดตแล้ว โปรดดูชุดตัวเลือกกระบวนงานที่เก็บไว้
Eduardo Cuomo

1
นี่ไม่ใช่วิธีการที่ดี ตามความเห็นของ 700 รุ่นอื่น ๆ ของคำตอบเดียวกันกับคำถามนี้ ยกเว้นฐานข้อมูลของคุณอยู่ในโหมดการกู้คืนอย่างง่ายเพื่อ จำกัด การบันทึกธุรกรรม
pimbrouwers

68

วิธีแก้ปัญหา @denver_citizen ที่ให้ไว้ด้านบนไม่ได้ผลสำหรับฉัน แต่ฉันชอบวิญญาณของมันดังนั้นฉันจึงแก้ไขบางสิ่ง:

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

เพื่อประโยชน์ของสาธารณะนี่คือสคริปต์ที่อัปเดต:

CREATE PROCEDURE [dbo].[truncate_non_empty_table]

  @TableToTruncate                 VARCHAR(64)

AS 

BEGIN

SET NOCOUNT ON

-- GLOBAL VARIABLES
DECLARE @i int
DECLARE @Debug bit
DECLARE @Recycle bit
DECLARE @Verbose bit
DECLARE @TableName varchar(80)
DECLARE @ColumnName varchar(80)
DECLARE @ReferencedTableName varchar(80)
DECLARE @ReferencedColumnName varchar(80)
DECLARE @ConstraintName varchar(250)

DECLARE @CreateStatement varchar(max)
DECLARE @DropStatement varchar(max)   
DECLARE @TruncateStatement varchar(max)
DECLARE @CreateStatementTemp varchar(max)
DECLARE @DropStatementTemp varchar(max)
DECLARE @TruncateStatementTemp varchar(max)
DECLARE @Statement varchar(max)

        -- 1 = Will not execute statements 
 SET @Debug = 0
        -- 0 = Will not create or truncate storage table
        -- 1 = Will create or truncate storage table
 SET @Recycle = 0
        -- 1 = Will print a message on every step
 set @Verbose = 1

 SET @i = 1
    SET @CreateStatement = 'ALTER TABLE [dbo].[<tablename>]  WITH NOCHECK ADD  CONSTRAINT [<constraintname>] FOREIGN KEY([<column>]) REFERENCES [dbo].[<reftable>] ([<refcolumn>])'
    SET @DropStatement = 'ALTER TABLE [dbo].[<tablename>] DROP CONSTRAINT [<constraintname>]'
    SET @TruncateStatement = 'TRUNCATE TABLE [<tablename>]'

-- Drop Temporary tables

IF OBJECT_ID('tempdb..#FKs') IS NOT NULL
    DROP TABLE #FKs

-- GET FKs
SELECT ROW_NUMBER() OVER (ORDER BY OBJECT_NAME(parent_object_id), clm1.name) as ID,
       OBJECT_NAME(constraint_object_id) as ConstraintName,
       OBJECT_NAME(parent_object_id) as TableName,
       clm1.name as ColumnName, 
       OBJECT_NAME(referenced_object_id) as ReferencedTableName,
       clm2.name as ReferencedColumnName
  INTO #FKs
  FROM sys.foreign_key_columns fk
       JOIN sys.columns clm1 
         ON fk.parent_column_id = clm1.column_id 
            AND fk.parent_object_id = clm1.object_id
       JOIN sys.columns clm2
         ON fk.referenced_column_id = clm2.column_id 
            AND fk.referenced_object_id= clm2.object_id
 --WHERE OBJECT_NAME(parent_object_id) not in ('//tables that you do not wont to be truncated')
 WHERE OBJECT_NAME(referenced_object_id) = @TableToTruncate
 ORDER BY OBJECT_NAME(parent_object_id)


-- Prepare Storage Table
IF Not EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Internal_FK_Definition_Storage')
   BEGIN
        IF @Verbose = 1
     PRINT '1. Creating Process Specific Tables...'

  -- CREATE STORAGE TABLE IF IT DOES NOT EXISTS
  CREATE TABLE [Internal_FK_Definition_Storage] 
  (
   ID int not null identity(1,1) primary key,
   FK_Name varchar(250) not null,
   FK_CreationStatement varchar(max) not null,
   FK_DestructionStatement varchar(max) not null,
   Table_TruncationStatement varchar(max) not null
  ) 
   END 
ELSE
   BEGIN
        IF @Recycle = 0
            BEGIN
                IF @Verbose = 1
       PRINT '1. Truncating Process Specific Tables...'

    -- TRUNCATE TABLE IF IT ALREADY EXISTS
    TRUNCATE TABLE [Internal_FK_Definition_Storage]    
      END
      ELSE
         PRINT '1. Process specific table will be recycled from previous execution...'
   END


IF @Recycle = 0
   BEGIN

  IF @Verbose = 1
     PRINT '2. Backing up Foreign Key Definitions...'

  -- Fetch and persist FKs             
  WHILE (@i <= (SELECT MAX(ID) FROM #FKs))
   BEGIN
    SET @ConstraintName = (SELECT ConstraintName FROM #FKs WHERE ID = @i)
    SET @TableName = (SELECT TableName FROM #FKs WHERE ID = @i)
    SET @ColumnName = (SELECT ColumnName FROM #FKs WHERE ID = @i)
    SET @ReferencedTableName = (SELECT ReferencedTableName FROM #FKs WHERE ID = @i)
    SET @ReferencedColumnName = (SELECT ReferencedColumnName FROM #FKs WHERE ID = @i)

    SET @DropStatementTemp = REPLACE(REPLACE(@DropStatement,'<tablename>',@TableName),'<constraintname>',@ConstraintName)
    SET @CreateStatementTemp = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@CreateStatement,'<tablename>',@TableName),'<column>',@ColumnName),'<constraintname>',@ConstraintName),'<reftable>',@ReferencedTableName),'<refcolumn>',@ReferencedColumnName)
    SET @TruncateStatementTemp = REPLACE(@TruncateStatement,'<tablename>',@TableName) 

    INSERT INTO [Internal_FK_Definition_Storage]
                        SELECT @ConstraintName, @CreateStatementTemp, @DropStatementTemp, @TruncateStatementTemp

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > Backing up [' + @ConstraintName + '] from [' + @TableName + ']'

    END   
    END   
    ELSE 
       PRINT '2. Backup up was recycled from previous execution...'

       IF @Verbose = 1
     PRINT '3. Dropping Foreign Keys...'

    -- DROP FOREING KEYS
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
             SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i)
    SET @Statement = (SELECT FK_DestructionStatement FROM [Internal_FK_Definition_Storage] WITH (NOLOCK) WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1


    IF @Verbose = 1
       PRINT '  > Dropping [' + @ConstraintName + ']'

             END     


    IF @Verbose = 1
       PRINT '4. Truncating Tables...'

    -- TRUNCATE TABLES
-- SzP: commented out as the tables to be truncated might also contain tables that has foreign keys
-- to resolve this the stored procedure should be called recursively, but I dont have the time to do it...          
 /*
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN

    SET @Statement = (SELECT Table_TruncationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > ' + @Statement
          END
*/          


    IF @Verbose = 1
       PRINT '  > TRUNCATE TABLE [' + @TableToTruncate + ']'

    IF @Debug = 1 
        PRINT 'TRUNCATE TABLE [' + @TableToTruncate + ']'
    ELSE
        EXEC('TRUNCATE TABLE [' + @TableToTruncate + ']')


    IF @Verbose = 1
       PRINT '5. Re-creating Foreign Keys...'

    -- CREATE FOREING KEYS
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
             SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i)
    SET @Statement = (SELECT FK_CreationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1


    IF @Verbose = 1
       PRINT '  > Re-creating [' + @ConstraintName + ']'

          END

    IF @Verbose = 1
       PRINT '6. Process Completed'


END

11
คำตอบนี้สมควรได้รับคะแนนโหวตมากขึ้น! ในความเป็นจริงฉันยินดีที่จะซื้อเบียร์ให้คุณถ้าฉันทำได้ปีเตอร์ :)
nsimeonov

นี่เป็นความช่วยเหลือที่ยอดเยี่ยมสำหรับฉันในวันนี้เพื่อล้างตารางข้อมูลขนาดใหญ่สำหรับการทดสอบอย่างรวดเร็วขอบคุณสำหรับการทำงานที่มีคุณภาพในเรื่องนี้
Craig Selbert

4
ขอบคุณสำหรับรหัสชิ้นนี้ แต่ระวังคุณควรเพิ่มตรรกะเพิ่มเติมเพื่อตรวจสอบ FK ที่ถูกปิดใช้งาน มิฉะนั้นคุณจะเปิดใช้งานข้อ จำกัด ที่ปิดใช้งานในปัจจุบัน
Andre Figueiredo

2
ฉันสร้างเวอร์ชันพร้อมคำแนะนำโดย @AndreFigueiredo ฉันวางมันลงบน Gitlab: gitlab.com/ranolfi/truncate-referenced-table อย่าลังเลที่จะรวมรหัสในคำตอบของคุณ
Marc.2377

1
นี่ยอดเยี่ยม แต่โปรดทราบว่าจะไม่ทำงานหากตารางของคุณไม่อยู่ในสคีมาเริ่มต้น (dbo)
Sidewinder94

19

ใช้คำสั่งต่อไปนี้หลังจากการลบแถวทั้งหมดในตารางนั้นโดยใช้คำสั่ง delete

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

แก้ไข: แก้ไขไวยากรณ์สำหรับ SQL Server


9
TRUNCATEหลีกเลี่ยงการบันทึกและเร็วกว่าDELETEมากสำหรับตารางขนาดใหญ่ ดังนั้นนี่จึงไม่ใช่ทางออกที่เท่าเทียมกันอย่างแท้จริง
siride

1
คำตอบนี้แตกต่างจากคำตอบนั้นซึ่งได้รับเมื่อหนึ่งปีก่อน?
Ofer Zelig

17

ดีเนื่องจากฉันไม่พบตัวอย่างของวิธีแก้ปัญหาที่ง่ายมากที่ฉันใช้ซึ่งก็คือ:

  1. วางกุญแจต่างประเทศ;
  2. ตัดทอนตาราง
  3. สร้างรหัสต่างประเทศอีกครั้ง

นี่มันไป:

1) ค้นหาชื่อคีย์ต่างประเทศที่ทำให้เกิดความล้มเหลว (ตัวอย่าง: FK_PROBLEM_REASON พร้อมฟิลด์IDจากตารางTABLE_OWNING_CONSTRAINT) 2) ลบคีย์นั้นออกจากตาราง:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) ตัดทอนตารางที่ต้องการ

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) เพิ่มคีย์ไปที่ตารางแรกอีกครั้ง:

ALTER TABLE TABLE_OWNING_CONSTRAINT ADD CONSTRAINT FK_PROBLEM_REASON FOREIGN KEY(ID) REFERENCES TABLE_TO_TRUNCATE (ID)

แค่นั้นแหละ.


สิ่งนี้ไม่ทำงานหากคุณมีหลายตารางที่มีการอ้างอิงคีย์ต่างประเทศ คุณจะต้องลบกุญแจต่างประเทศจำนวนมากออกจากฐานข้อมูลทั้งหมด
jbright

13

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

SET NOCOUNT ON

-- GLOBAL VARIABLES
DECLARE @i int
DECLARE @Debug bit
DECLARE @Recycle bit
DECLARE @Verbose bit
DECLARE @TableName varchar(80)
DECLARE @ColumnName varchar(80)
DECLARE @ReferencedTableName varchar(80)
DECLARE @ReferencedColumnName varchar(80)
DECLARE @ConstraintName varchar(250)

DECLARE @CreateStatement varchar(max)
DECLARE @DropStatement varchar(max)   
DECLARE @TruncateStatement varchar(max)
DECLARE @CreateStatementTemp varchar(max)
DECLARE @DropStatementTemp varchar(max)
DECLARE @TruncateStatementTemp varchar(max)
DECLARE @Statement varchar(max)

        -- 1 = Will not execute statements 
 SET @Debug = 0
        -- 0 = Will not create or truncate storage table
        -- 1 = Will create or truncate storage table
 SET @Recycle = 0
        -- 1 = Will print a message on every step
 set @Verbose = 1

 SET @i = 1
    SET @CreateStatement = 'ALTER TABLE [dbo].[<tablename>]  WITH NOCHECK ADD  CONSTRAINT [<constraintname>] FOREIGN KEY([<column>]) REFERENCES [dbo].[<reftable>] ([<refcolumn>])'
    SET @DropStatement = 'ALTER TABLE [dbo].[<tablename>] DROP CONSTRAINT [<constraintname>]'
    SET @TruncateStatement = 'TRUNCATE TABLE [<tablename>]'

-- Drop Temporary tables
DROP TABLE #FKs

-- GET FKs
SELECT ROW_NUMBER() OVER (ORDER BY OBJECT_NAME(parent_object_id), clm1.name) as ID,
       OBJECT_NAME(constraint_object_id) as ConstraintName,
       OBJECT_NAME(parent_object_id) as TableName,
       clm1.name as ColumnName, 
       OBJECT_NAME(referenced_object_id) as ReferencedTableName,
       clm2.name as ReferencedColumnName
  INTO #FKs
  FROM sys.foreign_key_columns fk
       JOIN sys.columns clm1 
         ON fk.parent_column_id = clm1.column_id 
            AND fk.parent_object_id = clm1.object_id
       JOIN sys.columns clm2
         ON fk.referenced_column_id = clm2.column_id 
            AND fk.referenced_object_id= clm2.object_id
 WHERE OBJECT_NAME(parent_object_id) not in ('//tables that you do not wont to be truncated')
 ORDER BY OBJECT_NAME(parent_object_id)


-- Prepare Storage Table
IF Not EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Internal_FK_Definition_Storage')
   BEGIN
        IF @Verbose = 1
     PRINT '1. Creating Process Specific Tables...'

  -- CREATE STORAGE TABLE IF IT DOES NOT EXISTS
  CREATE TABLE [Internal_FK_Definition_Storage] 
  (
   ID int not null identity(1,1) primary key,
   FK_Name varchar(250) not null,
   FK_CreationStatement varchar(max) not null,
   FK_DestructionStatement varchar(max) not null,
   Table_TruncationStatement varchar(max) not null
  ) 
   END 
ELSE
   BEGIN
        IF @Recycle = 0
            BEGIN
                IF @Verbose = 1
       PRINT '1. Truncating Process Specific Tables...'

    -- TRUNCATE TABLE IF IT ALREADY EXISTS
    TRUNCATE TABLE [Internal_FK_Definition_Storage]    
      END
      ELSE
         PRINT '1. Process specific table will be recycled from previous execution...'
   END

IF @Recycle = 0
   BEGIN

  IF @Verbose = 1
     PRINT '2. Backing up Foreign Key Definitions...'

  -- Fetch and persist FKs             
  WHILE (@i <= (SELECT MAX(ID) FROM #FKs))
   BEGIN
    SET @ConstraintName = (SELECT ConstraintName FROM #FKs WHERE ID = @i)
    SET @TableName = (SELECT TableName FROM #FKs WHERE ID = @i)
    SET @ColumnName = (SELECT ColumnName FROM #FKs WHERE ID = @i)
    SET @ReferencedTableName = (SELECT ReferencedTableName FROM #FKs WHERE ID = @i)
    SET @ReferencedColumnName = (SELECT ReferencedColumnName FROM #FKs WHERE ID = @i)

    SET @DropStatementTemp = REPLACE(REPLACE(@DropStatement,'<tablename>',@TableName),'<constraintname>',@ConstraintName)
    SET @CreateStatementTemp = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@CreateStatement,'<tablename>',@TableName),'<column>',@ColumnName),'<constraintname>',@ConstraintName),'<reftable>',@ReferencedTableName),'<refcolumn>',@ReferencedColumnName)
    SET @TruncateStatementTemp = REPLACE(@TruncateStatement,'<tablename>',@TableName) 

    INSERT INTO [Internal_FK_Definition_Storage]
                        SELECT @ConstraintName, @CreateStatementTemp, @DropStatementTemp, @TruncateStatementTemp

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > Backing up [' + @ConstraintName + '] from [' + @TableName + ']'

   END
    END   
    ELSE 
       PRINT '2. Backup up was recycled from previous execution...'

       IF @Verbose = 1
     PRINT '3. Dropping Foreign Keys...'

    -- DROP FOREING KEYS
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
             SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i)
    SET @Statement = (SELECT FK_DestructionStatement FROM [Internal_FK_Definition_Storage] WITH (NOLOCK) WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > Dropping [' + @ConstraintName + ']'
             END     

    IF @Verbose = 1
       PRINT '4. Truncating Tables...'

    -- TRUNCATE TABLES
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
    SET @Statement = (SELECT Table_TruncationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > ' + @Statement
          END

    IF @Verbose = 1
       PRINT '5. Re-creating Foreign Keys...'

    -- CREATE FOREING KEYS
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
             SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i)
    SET @Statement = (SELECT FK_CreationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > Re-creating [' + @ConstraintName + ']'
          END

    IF @Verbose = 1
       PRINT '6. Process Completed'

2
ระวัง. ฉันจะเพิ่มการดำเนินการอ้างอิงในคีย์ไปยังสคริปต์ของคุณไม่เช่นนั้นคุณจะสูญเสียการตั้งค่าแบบเรียงซ้อน
alphadogg

1
สิ่งนี้ไม่ได้ผลสำหรับฉัน แต่ฉันชอบวิญญาณของมันดังนั้นฉันจึงปรับเปลี่ยนบางสิ่ง: ทำให้ขั้นตอนการจัดเก็บเปลี่ยนวิธีการใส่กุญแจต่างประเทศและสร้างสคริปต์ต้นฉบับขึ้นใหม่ตัดทอนตารางอ้างอิงทั้งหมดซึ่งอาจผิดเมื่ออ้างอิง ไม่สามารถตัดทอนตารางได้เนื่องจากมีการอ้างอิงคีย์ต่างประเทศ ในรุ่นนี้เฉพาะตารางที่ระบุเป็นพารามิเตอร์จะถูกตัดทอนตารางอ้างอิงทั้งหมดควรถูกตัดทอนด้วยตนเองก่อนที่จะเรียกสคริปต์นี้ฉันโพสต์ข้อความแจ้งเตือนที่ได้รับการอัปเดตของเธรดนี้ที่นี่ stackoverflow.com/a/13249209/157591
Peter Szanto

1
@alphadogg มีวิธีใดในการค้นหาการดำเนินการอ้างอิงเหล่านั้นหรือไม่ ฉันแหย่ไปทั่วอินเทอร์เน็ตและดูเหมือนหาไม่พบ ฉันสามารถโพสต์เป็นคำถามทางการถ้าคุณต้องการ
ไมเคิล - ที่ไหน Clay Shirky

1
หมายเหตุถึงผู้เยี่ยมชมในอนาคต: มันอยู่ในsys.foreign_keysตาราง ( ข้อมูลอ้างอิง )
Michael - Where's Clay Shirky

@Michael: คุณสามารถใช้ INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/library/ms179987.aspx )
alphadogg

13

คุณสามารถทำตามขั้นตอนนี้โดยreseeding tableคุณสามารถลบข้อมูลของตาราง

delete from table_name
dbcc checkident('table_name',reseed,0)

หากมีข้อผิดพลาดเกิดขึ้นคุณจะต้องดำเนินการตารางหลักอีกครั้ง


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

9
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;

8
คำถามนี้เป็นคำถามเกี่ยวกับ MS SQL Server ซึ่งไม่ได้มีการตั้งค่า FOREIGN_KEY_CHECKS
Elezar

1
ฉันคิดว่านี่จะทำงานได้จาก MySQL แต่ไม่ใช่ MS SQL Server
Cocowalla

8

หากฉันเข้าใจอย่างถูกต้องสิ่งที่คุณต้องการทำคือให้มีสภาพแวดล้อมที่สะอาดสำหรับการตั้งค่าฐานข้อมูลที่เกี่ยวข้องกับการทดสอบการรวมระบบ

วิธีการของฉันที่นี่จะเป็นการวางสคีมาทั้งหมดและสร้างใหม่ในภายหลัง

เหตุผล:

  1. คุณอาจมีสคริปต์ "สร้างสคีมา" อยู่แล้ว การใช้งานซ้ำเพื่อแยกทดสอบทำได้ง่าย
  2. การสร้างสคีมานั้นค่อนข้างรวดเร็ว
  3. ด้วยวิธีการนั้นมันค่อนข้างง่ายในการตั้งค่าสคริปต์ของคุณเพื่อให้แต่ละฟิกซ์เจอร์สร้างสคีมาใหม่ (ด้วยชื่อชั่วคราว) จากนั้นคุณสามารถเริ่มใช้การติดตั้งทดสอบในแบบคู่ขนานทำให้ส่วนที่ช้าที่สุดของชุดทดสอบของคุณเร็วขึ้น .

1
ฉันต้องการที่จะ 'ตัดส่วน' สคีมาทั้งหมดไม่ได้ลบ ฉันต้องการจะทำในวิธีการตั้งค่าของการทดสอบการรวม การเรียกสคริปต์สร้างฐานข้อมูลจากภายในการทดสอบการรวมกันคือ ... ไม่ใช่วิธีแก้ปัญหาแรกที่ฉันจะไป
ripper234

7

พบที่อื่นในเว็บ

EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'
-- EXEC sp_MSForEachTable 'DELETE FROM ?' -- Uncomment to execute
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
EXEC sp_MSForEachTable 'ALTER TABLE ? ENABLE TRIGGER ALL'

3
น่าจะเป็น 'แก้ไขตาราง? ด้วยการตรวจสอบตรวจสอบ CONSTRAINT ALL '
Andriy M

20
-1: เพิ่งยืนยันว่านี่ไม่ได้ผลเลยเมื่อใช้คำสั่ง truncate ตามที่คำถามถาม ดูstackoverflow.com/questions/3843806/…
Lynn Crumbling

7

คุณไม่สามารถตัดทอนตารางได้หากคุณไม่ลดข้อ จำกัด ลง การปิดใช้งานยังไม่ทำงาน คุณต้องวางทุกอย่าง ฉันได้สร้างสคริปต์ที่วางข้อ จำกัด ทั้งหมดแล้วสร้างใหม่

ให้แน่ใจว่าได้ห่อไว้ในการทำธุรกรรม;)

SET NOCOUNT ON
GO

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

--DROP CONSTRAINT:

DECLARE @dynSQL varchar(MAX);

DECLARE cur CURSOR FOR
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
DROP CONSTRAINT ' + ForeignKeyConstraintName + '
'
FROM
@table

OPEN cur

FETCH cur into @dynSQL
WHILE @@FETCH_STATUS = 0 
BEGIN
    exec(@dynSQL)
    print @dynSQL

    FETCH cur into @dynSQL
END
CLOSE cur
DEALLOCATE cur
---------------------



   --HERE GOES YOUR TRUNCATES!!!!!
   --HERE GOES YOUR TRUNCATES!!!!!
   --HERE GOES YOUR TRUNCATES!!!!!

    truncate table your_table

   --HERE GOES YOUR TRUNCATES!!!!!
   --HERE GOES YOUR TRUNCATES!!!!!
   --HERE GOES YOUR TRUNCATES!!!!!

---------------------
--ADD CONSTRAINT:

DECLARE cur2 CURSOR FOR
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ')
'
FROM
@table

OPEN cur2

FETCH cur2 into @dynSQL
WHILE @@FETCH_STATUS = 0 
BEGIN
    exec(@dynSQL)

    print @dynSQL

    FETCH cur2 into @dynSQL
END
CLOSE cur2
DEALLOCATE cur2

6

@denver_citizen และคำตอบของ @Peter Szanto ไม่ได้ผลสำหรับฉัน แต่ฉันได้ปรับเปลี่ยนให้เป็นบัญชีสำหรับ:

  1. คีย์ผสม
  2. เปิดการลบและดำเนินการอัปเดต
  3. ตรวจสอบดัชนีเมื่อเพิ่มอีกครั้ง
  4. Schemas นอกเหนือจาก dbo
  5. หลายตารางพร้อมกัน
DECLARE @Debug bit = 0;

-- List of tables to truncate
select
    SchemaName, Name
into #tables
from (values 
    ('schema', 'table')
    ,('schema2', 'table2')
) as X(SchemaName, Name)


BEGIN TRANSACTION TruncateTrans;

with foreignKeys AS (
     SELECT 
        SCHEMA_NAME(fk.schema_id) as SchemaName
        ,fk.Name as ConstraintName
        ,OBJECT_NAME(fk.parent_object_id) as TableName
        ,SCHEMA_NAME(t.SCHEMA_ID) as ReferencedSchemaName
        ,OBJECT_NAME(fk.referenced_object_id) as ReferencedTableName
        ,fc.constraint_column_id
        ,COL_NAME(fk.parent_object_id, fc.parent_column_id) AS ColumnName
        ,COL_NAME(fk.referenced_object_id, fc.referenced_column_id) as ReferencedColumnName
        ,fk.delete_referential_action_desc
        ,fk.update_referential_action_desc
    FROM sys.foreign_keys AS fk
        JOIN sys.foreign_key_columns AS fc
            ON fk.object_id = fc.constraint_object_id
        JOIN #tables tbl 
            ON OBJECT_NAME(fc.referenced_object_id) = tbl.Name
        JOIN sys.tables t on OBJECT_NAME(t.object_id) = tbl.Name 
            and SCHEMA_NAME(t.schema_id) = tbl.SchemaName
            and t.OBJECT_ID = fc.referenced_object_id
)



select
    quotename(fk.ConstraintName) AS ConstraintName
    ,quotename(fk.SchemaName) + '.' + quotename(fk.TableName) AS TableName
    ,quotename(fk.ReferencedSchemaName) + '.' + quotename(fk.ReferencedTableName) AS ReferencedTableName
    ,replace(fk.delete_referential_action_desc, '_', ' ') AS DeleteAction
    ,replace(fk.update_referential_action_desc, '_', ' ') AS UpdateAction
    ,STUFF((
        SELECT ',' + quotename(fk2.ColumnName)
        FROM foreignKeys fk2 
        WHERE fk2.ConstraintName = fk.ConstraintName and fk2.SchemaName = fk.SchemaName
        ORDER BY fk2.constraint_column_id
        FOR XML PATH('')
    ),1,1,'') AS ColumnNames
    ,STUFF((
        SELECT ',' + quotename(fk2.ReferencedColumnName)
        FROM foreignKeys fk2 
        WHERE fk2.ConstraintName = fk.ConstraintName and fk2.SchemaName = fk.SchemaName
        ORDER BY fk2.constraint_column_id
        FOR XML PATH('')
    ),1,1,'') AS ReferencedColumnNames
into #FKs
from foreignKeys fk
GROUP BY fk.SchemaName, fk.ConstraintName, fk.TableName, fk.ReferencedSchemaName, fk.ReferencedTableName, fk.delete_referential_action_desc, fk.update_referential_action_desc



-- Drop FKs
select 
    identity(int,1,1) as ID,
    'ALTER TABLE ' + fk.TableName + ' DROP CONSTRAINT ' + fk.ConstraintName AS script
into #scripts
from #FKs fk

-- Truncate 
insert into #scripts
select distinct 
    'TRUNCATE TABLE ' + quotename(tbl.SchemaName) + '.' + quotename(tbl.Name) AS script
from #tables tbl

-- Recreate
insert into #scripts
select 
    'ALTER TABLE ' + fk.TableName + 
    ' WITH CHECK ADD CONSTRAINT ' + fk.ConstraintName + 
    ' FOREIGN KEY ('+ fk.ColumnNames +')' + 
    ' REFERENCES ' + fk.ReferencedTableName +' ('+ fk.ReferencedColumnNames +')' +
    ' ON DELETE ' + fk.DeleteAction COLLATE Latin1_General_CI_AS_KS_WS + ' ON UPDATE ' + fk.UpdateAction COLLATE Latin1_General_CI_AS_KS_WS AS script
from #FKs fk


DECLARE @script nvarchar(MAX);

DECLARE curScripts CURSOR FOR 
    select script
    from #scripts
    order by ID

OPEN curScripts

WHILE 1=1 BEGIN
    FETCH NEXT FROM curScripts INTO @script
    IF @@FETCH_STATUS != 0 BREAK;

    print @script;
    IF @Debug = 0
        EXEC (@script);
END
CLOSE curScripts
DEALLOCATE curScripts


drop table #scripts
drop table #FKs
drop table #tables


COMMIT TRANSACTION TruncateTrans;

4

truncate ไม่ได้ผลสำหรับฉันลบ + reseed เป็นวิธีที่ดีที่สุด ในกรณีที่มีพวกคุณบางคนที่จำเป็นต้องวนซ้ำตารางจำนวนมากเพื่อทำการลบ + reseed คุณอาจพบปัญหาเกี่ยวกับบางตารางที่ไม่มีคอลัมน์ข้อมูลระบุตัวตนรหัสต่อไปนี้จะตรวจสอบว่ามีคอลัมน์ข้อมูลประจำตัวอยู่หรือไม่ เพื่อดำเนินการต่อ

    EXEC ('DELETE FROM [schemaName].[tableName]')
    IF EXISTS (Select * from sys.identity_columns where object_name(object_id) = 'tableName')
    BEGIN
        EXEC ('DBCC CHECKIDENT ([schemaName.tableName], RESEED, 0)')
    END

4

ผมเขียนวิธีต่อไปนี้และพยายามที่จะแปรพวกเขาเพื่อให้คุณสามารถเรียกใช้พวกเขาในQuery documentหรือให้ประโยชน์SPกับพวกเขาได้อย่างง่ายดาย

A) ลบ

หากตารางของคุณมีระเบียนไม่ได้นับล้านรายการสิ่งนี้ใช้ได้ดีและยังไม่มีคำสั่ง Alter :

---------------------------------------------------------------
------------------- Just Fill Parameters Value ----------------
---------------------------------------------------------------
DECLARE @DbName AS NVARCHAR(30) = 'MyDb'         --< Db Name
DECLARE @Schema AS NVARCHAR(30) = 'dbo'          --< Schema
DECLARE @TableName AS NVARCHAR(30) = 'Book'      --< Table Name
------------------ /Just Fill Parameters Value ----------------

DECLARE @Query AS NVARCHAR(500) = 'Delete FROM ' + @TableName

EXECUTE sp_executesql @Query
SET @Query=@DbName+'.'+@Schema+'.'+@TableName
DBCC CHECKIDENT (@Query,RESEED, 0)
  • ในคำตอบข้างต้นของฉันวิธีการในการแก้ไขปัญหาที่กล่าวถึงในคำถามที่อยู่บนพื้นฐานของ@ s15199d คำตอบ

B) ตัดทอน

หากตารางของคุณมีบันทึกนับล้านหรือคุณไม่มีปัญหากับคำสั่ง Alterในรหัสของคุณให้ใช้อันนี้:

--   Book                               Student
--
--   |  BookId  | Field1 |              | StudentId |  BookId  |
--   ---------------------              ------------------------ 
--   |    1     |    A   |              |     2     |    1     |  
--   |    2     |    B   |              |     1     |    1     |
--   |    3     |    C   |              |     2     |    3     |  

---------------------------------------------------------------
------------------- Just Fill Parameters Value ----------------
---------------------------------------------------------------
DECLARE @DbName AS NVARCHAR(30) = 'MyDb'
DECLARE @Schema AS NVARCHAR(30) = 'dbo'
DECLARE @TableName_ToTruncate AS NVARCHAR(30) = 'Book'

DECLARE @TableName_OfOwnerOfConstraint AS NVARCHAR(30) = 'Student' --< Decelations About FK_Book_Constraint
DECLARE @Ref_ColumnName_In_TableName_ToTruncate AS NVARCHAR(30) = 'BookId' --< Decelations About FK_Book_Constraint
DECLARE @FK_ColumnName_In_TableOfOwnerOfConstraint AS NVARCHAR(30) = 'Fk_BookId' --< Decelations About FK_Book_Constraint
DECLARE @FK_ConstraintName AS NVARCHAR(30) = 'FK_Book_Constraint'                --< Decelations About FK_Book_Constraint
------------------ /Just Fill Parameters Value ----------------

DECLARE @Query AS NVARCHAR(2000)

SET @Query= 'ALTER TABLE '+@TableName_OfOwnerOfConstraint+' DROP CONSTRAINT '+@FK_ConstraintName
EXECUTE sp_executesql @Query

SET @Query= 'Truncate Table '+ @TableName_ToTruncate
EXECUTE sp_executesql @Query

SET @Query= 'ALTER TABLE '+@TableName_OfOwnerOfConstraint+' ADD CONSTRAINT '+@FK_ConstraintName+' FOREIGN KEY('+@FK_ColumnName_In_TableOfOwnerOfConstraint+') REFERENCES '+@TableName_ToTruncate+'('+@Ref_ColumnName_In_TableName_ToTruncate+')'
EXECUTE sp_executesql @Query
  • ในคำตอบข้างต้นของฉันวิธีการในการแก้ไขปัญหาที่กล่าวถึงในคำถามที่อยู่บนพื้นฐานของ@LauroWolffValenteSobrinho คำตอบ

  • หากคุณมีข้อ จำกัด มากกว่าหนึ่งข้อคุณควรเพิ่มรหัสเช่นฉันลงในข้อความค้นหาด้านบน

  • นอกจากนี้คุณสามารถเปลี่ยนรหัสฐานข้างต้น@SerjSagan คำตอบเพื่อปิดการใช้งานข้อ จำกัด


3

มันเป็นทางออกของปัญหานี้ ฉันใช้มันเพื่อแก้ไข PK แต่ก็คิดเหมือนกัน หวังว่านี่จะเป็นประโยชน์)

PRINT 'Script starts'

DECLARE @foreign_key_name varchar(255)
DECLARE @keycnt int
DECLARE @foreign_table varchar(255)
DECLARE @foreign_column_1 varchar(255)
DECLARE @foreign_column_2 varchar(255)
DECLARE @primary_table varchar(255)
DECLARE @primary_column_1 varchar(255)
DECLARE @primary_column_2 varchar(255)
DECLARE @TablN varchar(255)

-->> Type the primary table name
SET @TablN = ''
---------------------------------------------------------------------------------------    ------------------------------
--Here will be created the temporary table with all reference FKs
---------------------------------------------------------------------------------------------------------------------
PRINT 'Creating the temporary table'
select cast(f.name  as varchar(255)) as foreign_key_name
    , r.keycnt
    , cast(c.name as  varchar(255)) as foreign_table
    , cast(fc.name as varchar(255)) as  foreign_column_1
    , cast(fc2.name as varchar(255)) as foreign_column_2
    , cast(p.name as varchar(255)) as primary_table
    , cast(rc.name as varchar(255))  as primary_column_1
    , cast(rc2.name as varchar(255)) as  primary_column_2
    into #ConTab
    from sysobjects f
    inner join sysobjects c on  f.parent_obj = c.id 
    inner join sysreferences r on f.id =  r.constid
    inner join sysobjects p on r.rkeyid = p.id
    inner  join syscolumns rc on r.rkeyid = rc.id and r.rkey1 = rc.colid
    inner  join syscolumns fc on r.fkeyid = fc.id and r.fkey1 = fc.colid
    left join  syscolumns rc2 on r.rkeyid = rc2.id and r.rkey2 = rc.colid
    left join  syscolumns fc2 on r.fkeyid = fc2.id and r.fkey2 = fc.colid
    where f.type =  'F' and p.name = @TablN
 ORDER BY cast(p.name as varchar(255))
---------------------------------------------------------------------------------------------------------------------
--Cursor, below, will drop all reference FKs
---------------------------------------------------------------------------------------------------------------------
DECLARE @CURSOR CURSOR
/*Fill in cursor*/

PRINT 'Cursor 1 starting. All refernce FK will be droped'

SET @CURSOR  = CURSOR SCROLL
FOR
select foreign_key_name
    , keycnt
    , foreign_table
    , foreign_column_1
    , foreign_column_2
    , primary_table
    , primary_column_1
    , primary_column_2
    from #ConTab

OPEN @CURSOR

FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table,         @foreign_column_1, @foreign_column_2, 
                        @primary_table, @primary_column_1, @primary_column_2

WHILE @@FETCH_STATUS = 0
BEGIN

    EXEC ('ALTER TABLE ['+@foreign_table+'] DROP CONSTRAINT ['+@foreign_key_name+']')

FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, 
                         @primary_table, @primary_column_1, @primary_column_2
END
CLOSE @CURSOR
PRINT 'Cursor 1 finished work'
---------------------------------------------------------------------------------------------------------------------
--Here you should provide the chainging script for the primary table
---------------------------------------------------------------------------------------------------------------------

PRINT 'Altering primary table begin'

TRUNCATE TABLE table_name

PRINT 'Altering finished'

---------------------------------------------------------------------------------------------------------------------
--Cursor, below, will add again all reference FKs
--------------------------------------------------------------------------------------------------------------------

PRINT 'Cursor 2 starting. All refernce FK will added'
SET @CURSOR  = CURSOR SCROLL
FOR
select foreign_key_name
    , keycnt
    , foreign_table
    , foreign_column_1
    , foreign_column_2
    , primary_table
    , primary_column_1
    , primary_column_2
    from #ConTab

OPEN @CURSOR

FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, 
                         @primary_table, @primary_column_1, @primary_column_2

WHILE @@FETCH_STATUS = 0
BEGIN

    EXEC ('ALTER TABLE [' +@foreign_table+ '] WITH NOCHECK ADD  CONSTRAINT [' +@foreign_key_name+ '] FOREIGN KEY(['+@foreign_column_1+'])
        REFERENCES [' +@primary_table+'] (['+@primary_column_1+'])')

    EXEC ('ALTER TABLE [' +@foreign_table+ '] CHECK CONSTRAINT [' +@foreign_key_name+']')

FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, 
                         @primary_table, @primary_column_1, @primary_column_2
END
CLOSE @CURSOR
PRINT 'Cursor 2 finished work'
---------------------------------------------------------------------------------------------------------------------
PRINT 'Temporary table droping'
drop table #ConTab
PRINT 'Finish'

3

สำหรับMS SQLรุ่นที่ใหม่กว่าอย่างน้อยคุณสามารถปิดการใช้งานข้อ จำกัด ด้วยรหัสดังนี้:

ALTER TABLE Orders
NOCHECK CONSTRAINT [FK_dbo.Orders_dbo.Customers_Customer_Id]
GO

TRUNCATE TABLE Customers
GO

ALTER TABLE Orders
WITH CHECK CHECK CONSTRAINT [FK_dbo.Orders_dbo.Customers_Customer_Id]
GO

ฉันคิดว่าเรายอมรับแล้วว่ามันใช้ไม่ได้ อาจจะเป็นเวอร์ชั่นใหม่กว่านี้หรือ
Coops

2
Fwiw สิ่งนี้ไม่ทำงานในเวอร์ชันของ OP (2005) และไม่ทำงานในตัวต่อ (MSSQL2008)
CB

3

งานต่อไปนี้สำหรับฉันแม้จะมีข้อ จำกัด FK และรวมคำตอบต่อไปนี้เพื่อวางตารางที่ระบุเท่านั้น :


USE [YourDB];

DECLARE @TransactionName varchar(20) = 'stopdropandroll';

BEGIN TRAN @TransactionName;
set xact_abort on; /* automatic rollback https://stackoverflow.com/a/1749788/1037948 */
    -- ===== DO WORK // =====

    -- dynamic sql placeholder
    DECLARE @SQL varchar(300);

    -- LOOP: https://stackoverflow.com/a/10031803/1037948
    -- list of things to loop
    DECLARE @delim char = ';';
    DECLARE @foreach varchar(MAX) = 'Table;Names;Separated;By;Delimiter' + @delim + 'AnotherName' + @delim + 'Still Another';
    DECLARE @token varchar(MAX);
    WHILE len(@foreach) > 0
    BEGIN
        -- set current loop token
        SET @token = left(@foreach, charindex(@delim, @foreach+@delim)-1)
        -- ======= DO WORK // ===========

        -- dynamic sql (parentheses are required): https://stackoverflow.com/a/989111/1037948
        SET @SQL = 'DELETE FROM [' + @token + ']; DBCC CHECKIDENT (''' + @token + ''',RESEED, 0);'; -- https://stackoverflow.com/a/11784890
        PRINT @SQL;
        EXEC (@SQL);

        -- ======= // END WORK ===========
        -- continue loop, chopping off token
        SET @foreach = stuff(@foreach, 1, charindex(@delim, @foreach+@delim), '')
    END

    -- ===== // END WORK =====
-- review and commit
SELECT @@TRANCOUNT as TransactionsPerformed, @@ROWCOUNT as LastRowsChanged;
COMMIT TRAN @TransactionName;

บันทึก:

ฉันคิดว่ามันยังช่วยในการประกาศตารางตามลำดับที่คุณต้องการให้ลบ (เช่น kill dependencies ก่อน) ตามที่เห็นในคำตอบนี้แทนที่จะใช้ชื่อเฉพาะวนซ้ำคุณสามารถแทนที่ตารางทั้งหมดด้วย

EXEC sp_MSForEachTable 'DELETE FROM ?; DBCC CHECKIDENT (''?'',RESEED, 0);';

ไม่ได้พยายามสคริปต์อื่น ๆ เนื่องจากทุกคนระบุว่าพวกเขาไม่ทำงานเมื่อคุณมี Foreign Keys ดังนั้นฉันจึงลองอันนี้และอันนี้ก็หลอกให้ฉัน
Vivendi

1
DELETE ไม่ได้TRUNCATEเช่นเดียวกับ สิ่งนี้จะเติมบันทึกการทำธุรกรรมของคุณ
Dan Bechard

@ แดนอาจเป็นจุดที่ดี ที่ผมกล่าวถึงฉันเพียงแค่รวมคำตอบอื่น ๆ รอบ ๆ ที่นี่ ...
drzaus

@drzaus มันจะทำงานได้ดีสำหรับตารางเล็ก / กลาง แต่ฉันมีเซิร์ฟเวอร์ SQL ที่ใช้งานจริงออฟไลน์เนื่องจากคำสั่งลบกรอกบันทึกธุรกรรมซึ่งเต็มไปด้วยฮาร์ดดิสก์ อย่างน้อยที่สุดตรวจสอบให้แน่ใจว่าบันทึกธุรกรรมของคุณมีขนาดสูงสุดก่อนที่จะลองทำสิ่งนี้บนโต๊ะขนาดใหญ่
Dan Bechard

2

หากคำตอบเหล่านี้ไม่ได้ผลเหมือนในกรณีของฉันให้ทำสิ่งนี้:

  1. วางข้อ จำกัด
  2. ตั้งค่าทั้งหมดเพื่ออนุญาตเป็นโมฆะ
  3. ตัดทอนตาราง
  4. เพิ่มข้อ จำกัด ที่ถูกทิ้ง

โชคดี!


ตัวอย่าง sql เกี่ยวกับมัน?
Kiquenet

2

ลบจากนั้นรีเซ็ตการเพิ่มขึ้นอัตโนมัติ:

delete from tablename;

แล้วก็

ALTER TABLE tablename AUTO_INCREMENT = 1;

ขอบคุณสิ่งนี้ใช้ได้ดี
นาย Polywhirl

1

วิธีเดียวคือการวางกุญแจต่างประเทศก่อนที่จะทำการตัด และหลังจากตัดทอนข้อมูลคุณต้องสร้างดัชนีอีกครั้ง

สคริปต์ต่อไปนี้สร้าง SQL ที่จำเป็นสำหรับการปล่อยข้อ จำกัด คีย์ต่างประเทศทั้งหมด

DECLARE @drop NVARCHAR(MAX) = N'';

SELECT @drop += N'
ALTER TABLE ' + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
    + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS ct
  ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs 
  ON ct.[schema_id] = cs.[schema_id];

SELECT @drop

ถัดไปสคริปต์ต่อไปนี้สร้าง SQL ที่จำเป็นสำหรับการสร้างคีย์ต่างประเทศอีกครั้ง

DECLARE @create NVARCHAR(MAX) = N'';

SELECT @create += N'
ALTER TABLE ' 
   + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
   + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) 
   + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
   -- get all the columns in the constraint table
    FROM sys.columns AS c 
    INNER JOIN sys.foreign_key_columns AS fkc 
    ON fkc.parent_column_id = c.column_id
    AND fkc.parent_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'')
  + ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name)
  + '(' + STUFF((SELECT ',' + QUOTENAME(c.name)
   -- get all the referenced columns
    FROM sys.columns AS c 
    INNER JOIN sys.foreign_key_columns AS fkc 
    ON fkc.referenced_column_id = c.column_id
    AND fkc.referenced_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ');'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS rt -- referenced table
  ON fk.referenced_object_id = rt.[object_id]
INNER JOIN sys.schemas AS rs 
  ON rt.[schema_id] = rs.[schema_id]
INNER JOIN sys.tables AS ct -- constraint table
  ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs 
  ON ct.[schema_id] = cs.[schema_id]
WHERE rt.is_ms_shipped = 0 AND ct.is_ms_shipped = 0;

SELECT @create

เรียกใช้สคริปต์ที่สร้างขึ้นเพื่อปล่อยคีย์ต่างประเทศทั้งหมดตัดทอนตารางจากนั้นเรียกใช้สคริปต์ที่สร้างขึ้นเพื่อสร้างคีย์ต่างประเทศทั้งหมดอีกครั้ง

แบบสอบถามที่นำมาจากที่นี่


0

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


0

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

วิธีที่ดีที่สุดคือวิธีที่ยากหรือลำบาก นั่นคือ:

  • วางข้อ จำกัด
  • ตัดทอนตาราง
  • สร้างข้อ จำกัด อีกครั้ง

กระบวนการของฉันสำหรับการทำเช่นนี้เกี่ยวข้องกับขั้นตอนต่อไปนี้:

  1. ใน SSMS คลิกขวาที่ตารางในคำถามและเลือกดูการพึ่งพา
  2. จดบันทึกตารางที่อ้างถึง (ถ้ามี)
  3. ย้อนกลับไปใน object explorer ขยายโหนดKeysและจดบันทึก foreign keys (ถ้ามี)
  4. เริ่มการเขียนสคริปต์ (วาง / ตัดปลาย / สร้างใหม่)

สคริปต์ของลักษณะนี้ควรทำภายในbegin tranและcommit tranบล็อก


-3

ฉันเพิ่งพบว่าคุณสามารถใช้ตาราง TRUNCATE บนตารางหลักที่มีข้อ จำกัด ของรหัสต่างประเทศในเด็กตราบเท่าที่คุณปิดการใช้งานข้อ จำกัด บนตารางเด็กก่อน เช่น

คีย์ภาษาต่างประเทศ CONSTRAINT child_par_ref บนตารางลูกอ้างอิง PARENT_TABLE

ALTER TABLE CHILD_TABLE DISABLE CONSTRAINT child_par_ref;
TRUNCATE TABLE CHILD_TABLE;
TRUNCATE TABLE PARENT_TABLE;
ALTER TABLE CHILD_TABLE ENABLE CONSTRAINT child_par_ref;

1
นี่ไม่ใช่ไวยากรณ์ SQL Server ที่ถูกต้องสำหรับ ALTER TABLE ไม่มี {ENABLE | ปิดการใช้งาน} CONSTRAINT ดู: msdn.microsoft.com/en-us/library/ms190273.aspx
jason_ruz

-3

วิธีที่ง่ายที่สุด:
1 - ป้อนใน phpmyadmin
2 - คลิกที่ชื่อตารางในคอลัมน์ซ้าย
3 - คลิกในการทำงาน (เมนูด้านบน)
4 - คลิก "ล้างตาราง (TRUNCATE)
5 - ปิดการใช้งานกล่อง" เปิดใช้งานการตรวจสอบคีย์ต่างประเทศ "
6 - เสร็จสิ้น !

ลิงก์ไปยังบทช่วย
สอนการสอน: http://www.imageno.com/wz6gv1wuqajrpic.html
(ขออภัยฉันไม่มีชื่อเสียงพอที่จะอัปโหลดภาพได้ที่นี่: P)


2
OP ระบุ MSSQL คุณให้คำตอบพิเศษกับ MySQL
ปฏิรูป

-4

DELETE FROM <your table >;คุณอาจจะลอง

เซิร์ฟเวอร์จะแสดงชื่อของข้อ จำกัด และตารางและลบตารางที่คุณสามารถลบสิ่งที่คุณต้องการ


6
อ่านวลีที่สองของเขากับคำถาม เขารู้ว่าเขาสามารถทำได้ แต่นั่นไม่ใช่สิ่งที่เขาต้องการ
renanleandrof

-7
SET FOREIGN_KEY_CHECKS=0;
TRUNCATE table1;
TRUNCATE table2;
SET FOREIGN_KEY_CHECKS=1;

การอ้างอิง - ตัดปลายตารางข้อ จำกัด ของ foreign key

ทำงานให้ฉันใน MySQL


1
นอกเหนือจากเวอร์ชั่นที่ระบุมีอะไรผิดปกติกับสิ่งนี้อีกไหม มีการแนะนำให้ใช้หรือไม่ควรหลีกเลี่ยงทั้งหมด?
Andy Ibanez

1
@AndyIbanez MySQL เป็นผลิตภัณฑ์ที่แตกต่างอย่างสิ้นเชิงจาก MSSQL ไม่ใช่ MSSQL รุ่นอื่น
Dan Bechard

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