Bảng rút gọn không thể vì nó đang được tham chiếu bởi một ràng buộc FOREIGN KEY?


459

Sử dụng MSSQL2005, tôi có thể cắt một bảng có ràng buộc khóa ngoại nếu lần đầu tiên tôi cắt ngắn bảng con (bảng có khóa chính của mối quan hệ FK) không?

Tôi biết rằng tôi có thể

  • Sử dụng một DELETEkhông có mệnh đề where và sau đó RESEEDlà danh tính (hoặc)
  • Xóa FK, cắt bớt bảng và tạo lại FK.

Tôi nghĩ rằng miễn là tôi cắt ngắn bảng con trước cha mẹ, tôi sẽ ổn mà không thực hiện một trong các tùy chọn ở trên, nhưng tôi nhận được lỗi này:

Bảng rút gọn không thể 'Tên bảng' vì nó được tham chiếu bởi một ràng buộc FOREIGN KEY.

Câu trả lời:


379

Chính xác; bạn không thể cắt một bảng có ràng buộc FK trên đó.

Thông thường quy trình của tôi cho việc này là:

  1. Bỏ các ràng buộc
  2. Cắt bàn
  3. Tái tạo các ràng buộc.

(Tất cả trong một giao dịch, tất nhiên.)

Tất nhiên, điều này chỉ áp dụng nếu đứa trẻ đã bị cắt cụt. Nếu không, tôi đi một con đường khác, phụ thuộc hoàn toàn vào dữ liệu của tôi trông như thế nào. (Quá nhiều biến để vào đây.)

Các poster ban đầu xác định TẠI SAO đây là trường hợp; xem câu trả lời này để biết thêm chi tiết


73
"XÓA TỪ" không đặt lại các cột tăng tự động. Một cắt ngắn nào. Chúng không tương đương về chức năng.
robross0606

35
Cắt ngắn thường chính xác là những gì bạn muốn làm nếu bạn đang xóa một lượng lớn dữ liệu. Cắt một triệu hàng? Một tỷ? 1 ms ... vì vậy, @ M07, vui lòng không nói "xóa khỏi cách tiếp cận sạch hơn", vì điều đó không chính xác từ xa.
ctb

1
Sau khi xóa dữ liệu lớn, người dùng phải thu nhỏ các bảng và tệp nhật ký cũng để lấy lại không gian đĩa.
Muhammad Yousaf Sulahria

2
Nút Magic Shrink (hoặc tập lệnh) không được khuyên dùng 99%.
Tom Stickel

1
Và bạn sẽ làm điều đó như thế nào? Ví dụ yêu cầu?
jeromej

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

Lưu ý rằng đây có thể không phải là điều bạn muốn nếu bạn có hàng triệu hồ sơ, vì nó rất chậm.


Điều đó hữu ích, cách nhanh hơn là vô hiệu hóa và cho phép ràng buộc.
Sensei

Điều này sẽ chỉ làm việc cho bảng với ít dữ liệu. Đồng ý với @Pure
Dhanuka777

1
Điều này thật tuyệt vời khi bạn hoàn thành việc kiểm tra một lược đồ
ohmusama

3
Tôi không khuyên bạn nên đi tuyến đường này, vì bạn cũng có thể gặp phải lỗi này: Câu lệnh XÓA đã mâu thuẫn với ràng buộc TÀI LIỆU THAM KHẢO
sksallaj

Không làm việc cho tôi. Vẫn nhận được câu lệnh XÓA bị xung đột với ràng buộc TÀI LIỆU THAM KHẢO.
emirhosseini

192

TRUNCATE TABLElệnh DDL , nó không thể kiểm tra xem các bản ghi trong bảng có được tham chiếu bởi một bản ghi trong bảng con hay không.

Đây là lý do tại sao DELETEhoạt động và TRUNCATE TABLEkhông: bởi vì cơ sở dữ liệu có thể đảm bảo rằng nó không được tham chiếu bởi một bản ghi khác.


92

Không có 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)

Như thủ tục lưu trữ

https://github.com/reduardo7/TableTruncate

Lưu ý rằng đây có thể không phải là điều bạn muốn nếu bạn có hàng triệu hồ sơ, vì nó rất chậm.


3
sử dụng giá trị mới rese = 1 sau khi XÓA TỪ sẽ bắt đầu tất cả từ ID 2, thay vì 1. Từ Technet ( technet.microsoft.com/en-us/l Library / ms176057% 28Query.90% 29.aspx ) Nếu không có hàng nào được chèn vào bảng kể từ khi nó được tạo hoặc tất cả các hàng đã bị xóa bằng cách sử dụng câu lệnh TRUNCATE TABLE, hàng đầu tiên được chèn sau khi bạn chạy DBCC CHECKIDENT sử dụng new_reseed_value làm danh tính. Mặt khác, hàng tiếp theo được chèn sử dụng new_reseed_value + giá trị gia tăng hiện tại.
Zoran P.

@ZoranP. vui lòng xem biến thể Thủ tục được lưu trữ: github.com/reduardo7/TableTruncate
Eduardo Cuomo

4
KIỂM TRA DBCC ([Tên bảng], RESEED, 0) không phải 1
Pháo đài Tico

1
@TicoFortes Đăng cập nhật. Vui lòng xem biến thể Thủ tục được lưu trữ
Eduardo Cuomo

1
Đây không phải là một cách tiếp cận tốt. Như đã nhận xét bởi 700 phiên bản khác của cùng một câu trả lời cho câu hỏi này. UNLESS cơ sở dữ liệu của bạn ở chế độ khôi phục đơn giản, để hạn chế ghi nhật ký giao dịch.
pimbrouwers

68

Giải pháp @denver_citizen cung cấp ở trên không hiệu quả với tôi, nhưng tôi thích tinh thần của nó nên tôi đã sửa đổi một số điều:

  • làm cho nó trở thành một thủ tục lưu trữ
  • đã thay đổi cách các khóa ngoại được điền và tạo lại
  • tập lệnh gốc cắt ngắn tất cả các bảng được tham chiếu, điều này có thể gây ra lỗi vi phạm khóa ngoại khi bảng được tham chiếu có các tham chiếu khóa ngoại khác. Kịch bản lệnh này chỉ cắt ngắn bảng được chỉ định làm tham số. Tùy thuộc vào người dùng, để gọi thủ tục được lưu trữ này nhiều lần trên tất cả các bảng theo đúng thứ tự

Vì lợi ích của công chúng ở đây là kịch bản cập nhật:

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
Câu trả lời này xứng đáng được nhiều phiếu hơn! Thực tế tôi rất sẵn lòng mua cho bạn một cốc bia nếu tôi có thể, Peter :)
nsimeonov

Đây là một sự trợ giúp tuyệt vời cho tôi hôm nay để nhanh chóng xóa một số bảng dữ liệu lớn của họ để thử nghiệm, Cảm ơn vì chất lượng công việc này.
Craig Selbert 7/07/2016

4
Cảm ơn bạn cho đoạn mã này. Nhưng xem ra, bạn nên thêm một logic bổ sung để kiểm tra FK bị vô hiệu hóa. Nếu không, bạn sẽ kích hoạt các ràng buộc hiện đang bị vô hiệu hóa.
Andre Figueiredo

2
Tôi đã tạo một phiên bản với các đề xuất của @AndreFigueiredo. Tôi đang đưa nó lên Gitlab: gitlab.com/ranolfi/truncate-referenced-table . Hãy kết hợp mã để trả lời của bạn.
Marc.2377

1
Điều này thật tuyệt, nhưng lưu ý rằng nó sẽ không hoạt động nếu các bảng của bạn không nằm trong lược đồ (dbo) mặc định.
Sidewinder94

19

sử dụng lệnh sau khi xóa tất cả các hàng trong bảng đó bằng cách sử dụng câu lệnh xóa

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

EDIT: Sửa lỗi cú pháp cho SQL Server


9
TRUNCATEtránh nhật ký và nhanh hơn đáng kể so DELETEvới các bảng lớn. Như vậy, đây không phải là một giải pháp tương đương thực sự.
siride

1
Làm thế nào là câu trả lời này khác nhau từ một trong đó , mà đã được đưa ra một năm trước?
Ofer Zelig

17

Chà, vì tôi không tìm thấy ví dụ về giải pháp rất đơn giản mà tôi đã sử dụng, đó là:

  1. Đánh rơi khóa ngoại;
  2. Bàn cắt
  3. Tái tạo khóa ngoại

Nó đi từ đây:

1) Tìm tên khóa ngoại gây ra lỗi (ví dụ: FK_PROBLEM_REASON, với trường ID, từ bảng TABLE_OWNING_CONSTRAINT) 2) Xóa khóa đó khỏi bảng:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Cắt ngắn bảng muốn

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Thêm lại khóa vào bảng đầu tiên đó:

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

Đó là nó.


Điều này không hoạt động nếu bạn có nhiều bảng có tham chiếu khóa ngoài. Bạn sẽ phải loại bỏ rất nhiều hạn chế khóa ngoại trong toàn bộ cơ sở dữ liệu.
jbright

13

Đây là một kịch bản tôi đã viết để tự động hóa quá trình. Tôi hy vọng nó sẽ giúp.

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
Hãy cẩn thận. Tôi cũng sẽ thêm các hành động tham chiếu trên các phím vào tập lệnh của bạn hoặc bạn sẽ mất các cài đặt xếp tầng.
alphadogg

1
Điều này không phù hợp với tôi, nhưng tôi thích tinh thần của nó vì vậy tôi đã sửa đổi một số điều: làm cho nó trở thành một thủ tục được lưu trữ thay đổi cách các khóa ngoại được tạo và tạo lại tập lệnh gốc cắt bớt tất cả các bảng được tham chiếu, điều này có thể sai khi tham chiếu bảng không thể bị cắt vì nó cũng có các tham chiếu khóa ngoài. Trong phiên bản này, chỉ có bảng được chỉ định làm tham số sẽ bị cắt ngắn, tất cả các bảng được tham chiếu nên được cắt bớt bằng tay trước khi gọi tập lệnh này. Tôi đã đăng đoạn mã được cập nhật cho chủ đề này tại đây stackoverflow.com/a/13249209/157591
Peter Szanto

1
@alphadogg Có cách nào để tìm những hành động tham chiếu đó không? Tôi đã tìm kiếm trên internet và dường như không thể tìm thấy chúng. Tôi có thể đăng nó như một câu hỏi chính thức, nếu bạn muốn.
Michael - Clay Shirky ở đâu

1
Lưu ý cho khách truy cập trong tương lai: nó nằm trong sys.foreign_keysbảng. ( Tham khảo )
Michael - Clay Shirky ở đâu

@Michael: Bạn cũng có thể sử dụng Information_SCHema.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/l
Library / ms179987.aspx

13

bạn có thể làm theo bước này, bởi reseeding tablebạn có thể xóa dữ liệu của bảng.

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

nếu một số lỗi xuất hiện thì bạn phải đặt lại bảng chính.


1
Hãy nhớ rằng mặc dù điều này hoạt động tốt, nhật ký giao dịch sẽ tăng theo số lượng hồ sơ trong bảng so với 'bảng cắt ngắn' chỉ đưa một bản ghi vào nhật ký giao dịch. Không phải là một vấn đề lớn đối với hầu hết các bảng nhưng nếu có hàng triệu + hàng thì đó có thể là một vấn đề.
David

9
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;

8
Câu hỏi này là về MS SQL Server, không có cài đặt
FOREIGN_KEY_CHECKS

1
Tôi nghĩ rằng nó sẽ hoạt động từ MySQL, nhưng không phải MS SQL Server
Cocowalla

8

Nếu tôi hiểu chính xác, những gì bạn muốn làm là có một môi trường sạch sẽ được thiết lập cho DB liên quan đến các bài kiểm tra tích hợp.

Cách tiếp cận của tôi ở đây sẽ là bỏ toàn bộ lược đồ và tạo lại nó sau.

Lý do:

  1. Bạn có thể đã có một kịch bản "tạo lược đồ". Sử dụng lại nó để kiểm tra cách ly rất dễ dàng.
  2. Tạo một lược đồ là khá nhanh chóng.
  3. Với cách tiếp cận đó, khá dễ dàng để thiết lập tập lệnh của bạn để mỗi vật cố tạo một lược đồ MỚI (có tên tạm thời), và sau đó bạn có thể bắt đầu chạy song song các thử nghiệm, làm cho phần chậm nhất của bộ kiểm tra của bạn nhanh hơn nhiều .

1
Tôi muốn 'cắt bớt' tất cả các lược đồ, không bỏ nó. Tôi muốn làm điều đó trong phương pháp Thiết lập các bài kiểm tra tích hợp. Gọi tập lệnh tạo DB từ trong các thử nghiệm tích hợp là ... không phải là giải pháp đầu tiên tôi sẽ thực hiện.
ripper234

7

Tìm thấy ở nơi khác trên web

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
Có lẽ nên 'ALTER TABLE? KIỂM TRA KIỂM TRA CONSTRAINT TẤT CẢ '.
Andriy M

20
-1: Chỉ cần xác nhận rằng điều này hoàn toàn không hoạt động với lệnh cắt ngắn như được hỏi bởi câu hỏi. Xem stackoverflow.com/questions/3843806/ từ
Lynn Crumbled

7

Bạn không thể cắt bớt một bảng nếu bạn không bỏ các ràng buộc. Vô hiệu hóa cũng không hoạt động. bạn cần phải bỏ mọi thứ Tôi đã tạo một kịch bản bỏ tất cả các ràng buộc và sau đó tạo lại.

Hãy chắc chắn để bọc nó trong một giao dịch;)

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

Câu trả lời của @denver_citizen và @Peter Szanto không hoàn toàn phù hợp với tôi, nhưng tôi đã sửa đổi chúng thành tài khoản:

  1. Phím composite
  2. Hành động xóa và cập nhật
  3. Kiểm tra chỉ mục khi thêm lại
  4. Các lược đồ khác ngoài dbo
  5. Nhiều bảng cùng một lúc
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

cắt ngắn không làm việc cho tôi, xóa + reseed là cách tốt nhất. Trong trường hợp có một số bạn cần lặp lại số lượng lớn các bảng để thực hiện xóa + đổi lại, bạn có thể gặp sự cố với một số bảng không có cột định danh, đoạn mã sau kiểm tra xem có tồn tại cột nhận dạng hay không trước khi thử gieo hạt

    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

Tôi viết các cách sau và cố gắng tham số hóa chúng, vì vậy bạn có thể Chạy chúng trong một Query documentHoặc tạo hữu ích SPvới chúng một cách dễ dàng .

A) Xóa

Nếu bảng của bạn không có hàng triệu bản ghi thì nó hoạt động tốt và không có bất kỳ lệnh Alter nào :

---------------------------------------------------------------
------------------- 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)
  • Trong câu trả lời trên của tôi, phương pháp giải quyết vấn đề được đề cập trong câu hỏi được dựa trên câu trả lời @ s15199d .

B) Cắt ngắn

Nếu bảng của bạn có hàng triệu bản ghi hoặc bạn không gặp vấn đề gì với lệnh Alter trong mã của mình, thì hãy sử dụng bảng này:

--   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
  • Trong câu trả lời trên của tôi, phương pháp giải quyết vấn đề được đề cập trong câu hỏi được dựa trên câu trả lời @LauroWolffValenteSobrinho .

  • Nếu bạn có nhiều CONSTRAINT thì bạn nên nối các mã của nó như tôi vào truy vấn trên

  • Ngoài ra, bạn có thể thay đổi câu trả lời cơ sở mã @SerjSagan ở trên để vô hiệu hóa một ràng buộc cho phép


3

Đó là giải pháp của tôi về vấn đề này. Tôi đã sử dụng nó để thay đổi PK, nhưng ý tưởng tương tự. Hy vọng điều này sẽ hữu ích)

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

Đối với MS SQL, ít nhất là các phiên bản mới hơn, bạn chỉ có thể vô hiệu hóa các ràng buộc với mã như thế này:

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

Tôi nghĩ rằng chúng tôi thành lập ở trên rằng điều này không hoạt động? Có lẽ nó làm cho các phiên bản mới hơn?
Coops

2
Fwiw, điều này không hoạt động trong phiên bản của OP (2005) và cũng không hoạt động trong phiên bản kế nhiệm của nó (MSSQL2008).
CB

3

Các công việc sau đây đối với tôi ngay cả với các ràng buộc FK và kết hợp các câu trả lời sau để chỉ loại bỏ các bảng được chỉ định :


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;

Ghi chú:

Tôi nghĩ rằng nó vẫn giúp khai báo các bảng theo thứ tự bạn muốn xóa chúng (tức là loại bỏ các phụ thuộc trước). Như đã thấy trong câu trả lời này , thay vì lặp tên cụ thể, bạn có thể thay thế tất cả các bảng bằng

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

Không thực sự cố gắng với các tập lệnh khác vì mọi người nói rằng chúng không hoạt động khi bạn có Khóa ngoại. Vì vậy, tôi đã thử cái này và cái này đã giúp tôi.
Vivendi

1
DELETE không giống như TRUNCATE. Điều này sẽ điền vào nhật ký giao dịch của bạn.
Dan Bechard

@Dan, có lẽ là một điểm tốt; như tôi đã đề cập, tôi chỉ kết hợp các câu trả lời khác quanh đây ...
drzaus

@drzaus Nó sẽ hoạt động tốt đối với các bảng nhỏ / vừa, nhưng tôi đã có một máy chủ SQL sản xuất ngoại tuyến do lệnh xóa điền vào nhật ký giao dịch, chứa đầy đĩa cứng. Ít nhất, hãy đảm bảo nhật ký giao dịch của bạn có kích thước tối đa trước khi thử điều này trên một bảng lớn.
Dan Bechard

2

Nếu không có câu trả lời nào trong số này hoạt động như trong trường hợp của tôi, hãy làm điều này:

  1. Hạn chế thả
  2. Đặt tất cả các giá trị để cho phép null
  3. Bàn cắt
  4. Thêm các ràng buộc đã được loại bỏ.

Chúc may mắn!


bất kỳ mẫu sql về nó?
Kiquenet

2

Xóa sau đó đặt lại tự động tăng:

delete from tablename;

sau đó

ALTER TABLE tablename AUTO_INCREMENT = 1;

Cảm ơn, điều này đã làm việc tốt.
Ông Polywhirl

1

Cách duy nhất là bỏ các khóa ngoại trước khi thực hiện cắt ngắn. Và sau khi cắt dữ liệu, bạn phải tạo lại các chỉ mục.

Kịch bản sau đây tạo SQL cần thiết để loại bỏ tất cả các ràng buộc khóa ngoài.

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

Tiếp theo, tập lệnh sau tạo SQL cần thiết để tạo lại khóa ngoại.

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

Chạy tập lệnh được tạo để thả tất cả các khóa ngoại, cắt bớt các bảng và sau đó chạy tập lệnh được tạo để tạo lại tất cả các khóa ngoại.

Các truy vấn được lấy từ đây .


0

Trong SSMS tôi đã mở Sơ đồ hiển thị Khóa. Sau khi xóa Khóa và cắt bớt tệp tôi đã làm mới, sau đó tập trung trở lại vào Sơ đồ và tạo một bản cập nhật bằng cách xóa sau đó khôi phục hộp Nhận dạng. Việc lưu Sơ đồ đưa ra hộp thoại Lưu, hơn là hộp thoại "Thay đổi được thực hiện trong cơ sở dữ liệu trong khi bạn đang làm việc", bấm Có khôi phục Khóa, khôi phục lại từ bản sao được chốt trong Sơ đồ.


0

Nếu bạn đang thực hiện việc này ở bất kỳ tần suất nào, thậm chí là theo lịch trình, tôi hoàn toàn sẽ không bao giờ sử dụng câu lệnh DML. Chi phí ghi vào nhật ký giao dịch chỉ ở mức cao và đặt toàn bộ cơ sở dữ liệu vàoSIMPLE chế độ khôi phục để cắt bớt một bảng là vô lý.

Cách tốt nhất, không may là cách khó khăn hoặc lao động. Đó là:

  • Hạn chế thả
  • Bàn cắt
  • Tạo lại các ràng buộc

Quá trình của tôi để làm điều này bao gồm các bước sau:

  1. Trong SSMS, nhấp chuột phải vào bảng được đề cập và chọn Xem phụ thuộc
  2. Lưu ý các bảng được tham chiếu (nếu có)
  3. Quay lại trình thám hiểm đối tượng, mở rộng nút Phím và ghi chú các khóa ngoại (nếu có)
  4. Bắt đầu viết kịch bản (thả / cắt / tạo lại)

Các kịch bản có tính chất này nên được thực hiện trong một begin trancommit trankhối.


-3

Tôi vừa phát hiện ra rằng bạn có thể sử dụng bảng TRUNCATE trên bảng cha với các ràng buộc khóa ngoài đối với trẻ miễn là bạn BẮT ĐẦU các ràng buộc trên bảng con trước. Ví dụ

Khóa ngoại CONSTRAINT child_par_Vf trên bảng con, tham chiếu 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
Đây không phải là cú pháp SQL Server hợp lệ cho ALTER TABLE. Không có {ENABLE | TUYỆT VỜI} CONSTRAINT. Xem: msdn.microsoft.com/en-us/l
Library / ms190273.aspx

-3

Cách dễ nhất:
1 - Nhập vào phpmyadmin
2 - Nhấp vào tên bảng ở cột bên trái
3 - Nhấp vào Hoạt động (menu trên cùng)
4 - Nhấp vào "Làm trống bảng (TRUNCATE)
5 - Tắt hộp" Bật kiểm tra khóa ngoài "
6 - Xong !

Liên kết đến hướng dẫn hình ảnh
Hướng dẫn: http://www.imageno.com/wz6gv1wuqajrpic.html
(xin lỗi, tôi không có đủ danh tiếng để tải lên hình ảnh ở đây: P)


2
OP đã nêu MSSQL. Bạn đã đưa ra một câu trả lời dành riêng cho MySQL.
cải cách

-4

Bạn có thể thử DELETE FROM <your table >;.

Máy chủ sẽ hiển thị cho bạn tên của hạn chế và bảng và xóa bảng đó bạn có thể xóa những gì bạn cần.


6
Đọc cụm từ thứ hai của anh ấy về câu hỏi. Anh ta biết mình có thể làm điều đó, nhưng đó không phải là điều anh ta muốn
renanleandrof 18/07/13

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

tài liệu tham khảo - cắt bớt bảng ràng buộc khóa ngoại

Làm việc cho tôi trong MYSQL


1
Khác với phiên bản được chỉ định, có điều gì khác với cái này không? Nó sẽ được khuyến khích sử dụng nó, hoặc tránh nó hoàn toàn?
Andy Ibanez

1
@AndyIbanez MySQL là một sản phẩm hoàn toàn khác với MSSQL, không phải là một phiên bản khác của MSSQL.
Dan Bechard

1
câu trả lời đúng của nó Tôi không biết tại sao mọi người lại cho tiêu cực
sunil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.