Tidak dapat memotong tabel karena direferensikan oleh batasan KUNCI ASING?


459

Menggunakan MSSQL2005, bisakah saya memotong tabel dengan batasan kunci asing jika saya pertama memotong tabel anak (tabel dengan kunci utama hubungan FK)?

Saya tahu bahwa saya juga bisa

  • Gunakan DELETEklausa tanpa tempat dan kemudian RESEEDidentitas (atau)
  • Hapus FK, potong tabel, dan buat ulang FK.

Saya pikir selama saya memotong tabel anak sebelum orang tua, saya akan baik-baik saja tanpa melakukan salah satu opsi di atas, tapi saya mendapatkan kesalahan ini:

Tidak dapat memotong tabel 'TableName' karena sedang direferensikan oleh batasan KUNCI ASING.

Jawaban:


379

Benar; Anda tidak dapat memotong tabel yang memiliki batasan FK di atasnya.

Biasanya proses saya untuk ini adalah:

  1. Jatuhkan kendala
  2. Pangkas meja
  3. Buat kembali kendala.

(Semua dalam transaksi, tentu saja.)

Tentu saja, ini hanya berlaku jika anak sudah terpotong. Kalau tidak, saya pergi ke rute yang berbeda, sepenuhnya tergantung pada seperti apa data saya. (Terlalu banyak variabel untuk masuk ke sini.)

Poster asli ditentukan MENGAPA hal ini terjadi; lihat jawaban ini untuk lebih jelasnya.


73
"DELETE FROM" tidak mengatur ulang kolom penambahan otomatis. Memotong tidak. Mereka tidak setara secara fungsional.
robross0606

35
Memotong sering kali persis apa yang ingin Anda lakukan jika Anda menghapus data dalam jumlah besar. Memotong satu juta baris? Satu miliar? 1 ms ... jadi, @ M07, tolong jangan katakan "hapus dari pendekatan lebih bersih", karena itu tidak akurat dari jarak jauh.
ctb

1
Setelah menghapus data besar, pengguna harus mengecilkan tabel dan mencatat file juga untuk mendapatkan kembali ruang disk.
Muhammad Yousaf Sulahria

2
Tombol Magic Shrink (atau skrip) tidak disarankan sebanyak 99%.
Tom Stickel

1
Dan bagaimana Anda akan melakukannya? Contoh permintaan?
jeromej

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

Perhatikan bahwa ini mungkin bukan yang Anda inginkan jika Anda memiliki jutaan catatan, karena ini sangat lambat.


Itu bermanfaat, cara yang lebih cepat daripada menonaktifkan dan mengaktifkan kendala.
sensei

Ini hanya akan berfungsi untuk tabel dengan sedikit data. Setuju dengan @ Pure
Dhanuka777

1
Ini bagus untuk ketika Anda selesai menguji skema
ohmusama

3
Saya tidak akan menyarankan menempuh rute ini, karena Anda mungkin juga mendapatkan kesalahan ini: Pernyataan DELETE bertentangan dengan batasan REFERENSI
sksallaj

Tidak bekerja untuk saya. Pernyataan DELETE masih bertentangan dengan batasan REFERENSI.
emirhosseini

192

Karena TRUNCATE TABLEmerupakan perintah DDL , itu tidak dapat memeriksa untuk melihat apakah catatan di tabel sedang direferensikan oleh catatan di tabel anak.

Inilah sebabnya mengapa DELETEberhasil dan TRUNCATE TABLEtidak: karena database dapat memastikan bahwa itu tidak dirujuk oleh catatan lain.


92

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

Seperti Prosedur Yang Disimpan

https://github.com/reduardo7/TableTruncate

Perhatikan bahwa ini mungkin bukan yang Anda inginkan jika Anda memiliki jutaan catatan, karena ini sangat lambat.


3
menggunakan nilai baru reeed = 1 setelah DELETE FROM akan memulai semua dari ID 2, bukan 1. Dari Technet ( technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx ) Jika tidak ada baris telah disisipkan ke tabel sejak dibuat, atau semua baris telah dihapus dengan menggunakan pernyataan TRUNCATE TABLE, baris pertama dimasukkan setelah Anda menjalankan DBCC CHECKIDENT menggunakan new_reseed_value sebagai identitas. Jika tidak, baris berikutnya yang disisipkan menggunakan new_reseed_value + nilai kenaikan saat ini.
Zoran P.

@ZoranP. silakan lihat varian Stored Procedure: github.com/reduardo7/TableTruncate
Eduardo Cuomo

4
DBCC CHECKIDENT ([TableName], RESEED, 0) bukan 1
Tico Fortes

1
@TicoFortes Post diperbarui. Silakan lihat varian Stored Procedure
Eduardo Cuomo

1
Ini bukan pendekatan yang baik. Seperti yang dikomentari oleh 700 versi lain dari jawaban yang sama untuk pertanyaan ini. KECUALI database Anda berada dalam mode pemulihan sederhana, untuk membatasi pencatatan transaksi.
pimbrouwers

68

Solusi @denver_citizen yang diberikan di atas tidak bekerja untuk saya, tapi saya suka semangatnya jadi saya memodifikasi beberapa hal:

  • menjadikannya prosedur yang tersimpan
  • mengubah cara kunci asing diisi dan diciptakan kembali
  • script asli memotong semua tabel yang direferensikan, ini dapat menyebabkan kesalahan pelanggaran kunci asing ketika tabel referensi memiliki referensi kunci asing lainnya. Script ini hanya memotong tabel yang ditentukan sebagai parameter. Terserah pengguna, untuk memanggil prosedur tersimpan ini beberapa kali pada semua tabel dalam urutan yang benar

Untuk kepentingan publik, berikut adalah skrip yang diperbarui:

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
Jawaban ini layak mendapat lebih banyak suara! Sebenarnya saya dengan senang hati akan membelikan Anda bir jika saya bisa, Peter :)
nsimeonov

Ini sangat membantu saya hari ini untuk dengan cepat menghapus beberapa tabel besar data mereka untuk pengujian, Terima kasih atas kerja berkualitas untuk ini.
Craig Selbert

4
Terima kasih atas kode ini. Tapi hati-hati, Anda harus menambahkan logika tambahan untuk memeriksa FK yang dinonaktifkan. Jika tidak, Anda akan mengaktifkan batasan yang saat ini dinonaktifkan.
Andre Figueiredo

2
Saya membuat versi dengan saran dari @AndreFigueiredo. Saya meletakkannya di Gitlab: gitlab.com/ranolfi/truncate-referenced-table . Jangan ragu untuk memasukkan kode ke jawaban Anda.
Marc.2377

1
Ini bagus, tetapi harap dicatat bahwa itu tidak akan berfungsi jika tabel Anda tidak dalam skema default (dbo).
Sidewinder94

19

gunakan perintah berikut setelah penghapusan semua baris dalam tabel itu dengan menggunakan pernyataan delete

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

EDIT: Sintaks terkoreksi untuk SQL Server


9
TRUNCATEmenghindari log dan jauh lebih cepat daripada DELETEtabel besar. Dengan demikian, ini bukan solusi setara sejati.
siride

1
Bagaimana jawaban ini berbeda dari yang , yang diberikan satu tahun sebelumnya?
Ofer Zelig

17

Nah, karena saya tidak menemukan contoh dari yang sangat sederhana solusi yang saya digunakan, yaitu:

  1. Jatuhkan kunci asing;
  2. Tabel terpotong
  3. Buat kunci asing

Ini dia:

1) Temukan nama kunci asing yang menyebabkan kegagalan (misalnya: FK_PROBLEM_REASON, dengan bidang ID, dari tabel TABLE_OWNING_CONSTRAINT) 2) Hapus kunci itu dari tabel:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Memotong tabel yang diinginkan

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Tambahkan kembali kunci ke tabel pertama itu:

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

Itu dia.


Ini tidak berfungsi jika Anda memiliki beberapa tabel dengan referensi kunci asing. Anda harus menghapus banyak pembatasan kunci asing di seluruh database.
jbright

13

Berikut adalah skrip yang saya tulis untuk mengotomatiskan proses. Saya harap ini membantu.

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
Hati-hati. Saya juga akan menambahkan tindakan referensial pada kunci skrip Anda atau Anda akan kehilangan pengaturan kaskade.
alphadogg

1
ini tidak bekerja untuk saya, tapi saya suka semangatnya jadi saya memodifikasi beberapa hal: menjadikannya prosedur tersimpan mengubah cara kunci asing diisi dan membuat ulang skrip asli memotong semua tabel yang direferensikan, ini bisa salah ketika direferensikan tabel tidak dapat dipotong karena juga memiliki referensi kunci asing. Dalam versi ini hanya tabel yang ditentukan sebagai parameter yang akan dipotong, semua tabel yang direferensikan harus dipotong secara manual sebelum memanggil skrip ini. Saya memposting tolution yang diperbarui ke utas ini di sini stackoverflow.com/a/13249209/157591
Peter Szanto

1
@alphadogg Apakah ada cara untuk menemukan tindakan referensial itu? Saya sudah mencari-cari di internet, dan sepertinya tidak bisa menemukannya. Saya dapat mempostingnya sebagai pertanyaan formal, jika Anda mau.
Michael - Di mana Clay Shirky

1
Catatan untuk pengunjung masa depan: ada di sys.foreign_keystabel. ( Referensi )
Michael - Di mana Clay Shirky

@Michael: Anda juga dapat menggunakan INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/library/ms179987.aspx )
alphadogg

13

Anda dapat mengikuti langkah ini, Dengan reseeding tableAnda dapat menghapus data tabel.

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

jika beberapa kesalahan terjadi maka Anda harus me-reseed tabel utama.


1
Perlu diingat bahwa meskipun ini berfungsi dengan baik, log transaksi akan bertambah dengan jumlah catatan di tabel vs. 'truncate table' yang hanya menempatkan satu catatan di log transaksi. Bukan masalah besar untuk sebagian besar tabel tetapi jika ada jutaan + baris maka itu bisa menjadi masalah.
David

9
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;

8
Pertanyaan ini tentang MS SQL Server, yang tidak memiliki pengaturan FOREIGN_KEY_CHECKS
Elezar

1
Saya pikir ini akan bekerja dari MySQL, tetapi tidak MS SQL Server
Cocowalla

8

Jika saya mengerti dengan benar, apa yang ingin Anda lakukan adalah memiliki lingkungan yang bersih untuk diatur untuk DB yang melibatkan tes integrasi.

Pendekatan saya di sini adalah untuk membatalkan seluruh skema dan membuatnya kembali nanti.

Alasan:

  1. Anda mungkin sudah memiliki skrip "buat skema". Menggunakannya kembali untuk isolasi tes mudah.
  2. Membuat skema cukup cepat.
  3. Dengan pendekatan itu, sangat mudah untuk mengatur skrip Anda agar setiap fixture membuat skema BARU (dengan nama sementara), dan kemudian Anda dapat mulai menjalankan perlengkapan tes secara paralel, membuat bagian paling lambat dari test suite Anda menjadi lebih cepat. .

1
Saya ingin 'memotong' semua skema, bukan menjatuhkannya. Saya ingin melakukannya dalam metode pengaturan tes integrasi. Memanggil skrip pembuatan DB dari dalam tes integrasi adalah ... bukan solusi pertama yang akan saya tuju.
ripper234

7

Ditemukan di tempat lain di 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
Haruskah mungkin 'ALTER TABLE? DENGAN LIHAT CHECK CONSTRAINT ALL '.
Andriy M

20
-1: Baru saja mengkonfirmasi ini tidak berfungsi sama sekali dengan perintah truncate seperti yang ditanyakan oleh pertanyaan. Lihat stackoverflow.com/questions/3843806/ā€¦
Lynn Crumbling

7

Anda tidak dapat memotong tabel jika Anda tidak menghilangkan kendala. Penonaktifan juga tidak berfungsi. Anda perlu Drop segalanya. Saya telah membuat skrip yang menghapus semua batasan lalu membuat ulang kemudian.

Pastikan untuk membungkusnya dalam transaksi;)

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

Jawaban @denver_citizen dan @Peter Szanto tidak cukup untuk saya, tetapi saya memodifikasinya untuk menjelaskan:

  1. Kunci Komposit
  2. Tindakan Hapus dan Aktif Perbarui
  3. Memeriksa indeks saat menambahkan kembali
  4. Skema selain dbo
  5. Beberapa tabel sekaligus
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 tidak berfungsi untuk saya, hapus + reseed adalah jalan keluar terbaik. Jika ada beberapa dari Anda di luar sana yang perlu mengulangi sejumlah besar tabel untuk melakukan delete + reseed, Anda mungkin mengalami masalah dengan beberapa tabel yang tidak memiliki kolom identitas, kode berikut memeriksa apakah kolom identitas ada sebelum mencoba untuk diperbanyak

    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

Saya menulis cara-cara berikut dan mencoba untuk membuat parameternya, sehingga Anda dapat menjalankannya dalam Query documentatau Membuatnya berguna SPdengan mudah .

A) Hapus

Jika tabel Anda tidak memiliki jutaan rekaman, ini berfungsi dengan baik dan tidak memiliki perintah 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)
  • Dalam jawaban saya di atas, metode untuk menyelesaikan masalah yang disebutkan dalam pertanyaan didasarkan pada jawaban @ s15199d .

B) Potong

Jika tabel Anda memiliki jutaan catatan atau Anda tidak memiliki masalah dengan perintah Alter dalam kode Anda, maka gunakan yang ini:

--   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
  • Dalam jawaban saya di atas, metode untuk menyelesaikan masalah yang disebutkan dalam pertanyaan didasarkan pada jawaban @LauroWolffValenteSobrinho .

  • Jika Anda memiliki lebih dari satu CONSTRAINT maka Anda harus menambahkan kode-kodenya seperti saya ke kueri di atas

  • Anda juga dapat mengubah atas basis kode @SerjSagan jawaban menonaktifkan mengaktifkan kendala


3

Ini solusi saya untuk masalah ini. Saya menggunakannya untuk mengubah PK, tetapi gagasannya sama. Semoga ini bermanfaat)

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

Untuk MS SQL, setidaknya versi yang lebih baru, Anda bisa menonaktifkan batasan dengan kode seperti ini:

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

Saya pikir kami menetapkan di atas bahwa ini tidak berhasil? Mungkin itu untuk versi yang lebih baru?
Coops

2
Namun, ini tidak berfungsi dalam versi OP (2005), dan juga tidak bekerja pada penggantinya (MSSQL2008).
CB

3

Berikut ini berfungsi untuk saya bahkan dengan kendala FK, dan menggabungkan jawaban berikut untuk hanya menjatuhkan tabel yang ditentukan :


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;

catatan:

Saya pikir ini masih membantu untuk mendeklarasikan tabel dalam urutan yang Anda ingin mereka hapus (yaitu membunuh dependensi terlebih dahulu). Seperti yang terlihat dalam jawaban ini , alih-alih mengulang nama tertentu, Anda dapat mengganti semua tabel dengan

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

Tidak benar-benar mencoba ke skrip lain karena semua orang menyatakan bahwa mereka tidak berfungsi ketika Anda memiliki Kunci Asing. Jadi saya mencoba yang ini dan yang ini melakukan trik untuk saya.
Vivendi

1
DELETE tidak sama dengan TRUNCATE. Ini akan mengisi log transaksi Anda.
Dan Bechard

@ Dan, mungkin poin yang bagus; seperti yang saya sebutkan saya baru saja menggabungkan jawaban lain di sekitar sini ...
drzaus

@drzaus Ini akan berfungsi dengan baik untuk tabel kecil / menengah, tapi saya sudah punya server SQL produksi offline karena perintah hapus mengisi log transaksi, yang mengisi hard disk. Paling tidak, pastikan log transaksi Anda memiliki ukuran maksimal sebelum mencoba ini di meja besar.
Dan Bechard

2

Jika tidak ada jawaban yang berfungsi seperti pada kasus saya, lakukan ini:

  1. Jatuhkan batasan
  2. Tetapkan semua nilai untuk mengizinkan nol
  3. Tabel terpotong
  4. Tambahkan batasan yang dijatuhkan.

Semoga berhasil!


ada sampel sql tentang itu?
Kiquenet

2

Hapus lalu setel ulang kenaikan otomatis:

delete from tablename;

kemudian

ALTER TABLE tablename AUTO_INCREMENT = 1;

Terima kasih, ini bekerja dengan baik.
Tn. Polywhirl

1

Satu-satunya cara adalah dengan menjatuhkan kunci asing sebelum melakukan pemotongan. Dan setelah memotong data, Anda harus membuat kembali indeks.

Script berikut menghasilkan SQL yang diperlukan untuk menjatuhkan semua batasan kunci asing.

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

Selanjutnya, skrip berikut menghasilkan SQL yang diperlukan untuk membuat kembali kunci asing.

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

Jalankan skrip yang dibuat untuk menjatuhkan semua kunci asing, memotong tabel, dan kemudian menjalankan skrip yang dihasilkan untuk membuat kembali semua kunci asing.

Pertanyaan diambil dari sini .


0

Di SSMS saya punya Diagram terbuka menunjukkan Kunci. Setelah menghapus Kunci dan memotong file saya menyegarkan kemudian fokus kembali pada Diagram dan membuat pembaruan dengan menghapus lalu mengembalikan kotak Identity. Menyimpan Diagram memunculkan kotak dialog Simpan, daripada kotak dialog "Perubahan dibuat dalam database saat Anda bekerja", mengklik Ya mengembalikan Kunci, mengembalikannya dari salinan yang terkunci di Diagram.


0

Jika Anda melakukan ini pada frekuensi apa pun, heck bahkan pada jadwal, saya pasti tidak akan pernah menggunakan pernyataan DML. Biaya penulisan untuk log transaksi hanya untuk tinggi, dan pengaturan seluruh database ke SIMPLEmode pemulihan untuk memotong satu tabel adalah konyol.

Cara terbaik, sayangnya cara yang sulit atau melelahkan. Makhluk itu:

  • Jatuhkan batasan
  • Tabel terpotong
  • Buat kembali kendala

Proses saya untuk melakukan ini melibatkan langkah-langkah berikut:

  1. Dalam SSMS klik kanan pada tabel yang dimaksud, dan pilih Lihat Dependensi
  2. Perhatikan tabel yang direferensikan (jika ada)
  3. Kembali ke objek explorer, perluas simpul Tombol dan catat kunci asing (jika ada)
  4. Mulai scripting (drop / truncate / re-create)

Skrip seperti ini harus dilakukan dalam a begin trandan commit tranblok.


-3

Saya baru saja menemukan bahwa Anda dapat menggunakan tabel TRUNCATE pada tabel induk dengan batasan kunci asing pada anak selama Anda MENONAKTIFKAN kendala pada tabel anak terlebih dahulu. Misalnya

CONSTRAINT kunci asing child_par_ref di tabel anak, referensi 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
Ini bukan sintaks SQL Server yang valid untuk ALTER TABLE. Tidak ada {ENABLE | DISABLE} CONSTRAINT. Lihat: msdn.microsoft.com/en-us/library/ms190273.aspx
jason_ruz

-3

Cara termudah:
1 - Masukkan di phpmyadmin
2 - Klik pada nama tabel di kolom kiri
3 - Klik di Operasi (menu atas)
4 - Klik "Kosongkan tabel (TRUNCATE)
5 - Nonaktifkan kotak" Aktifkan pemeriksaan kunci asing "
6 - Selesai !

Tautan ke tutorial gambar
Tutorial: http://www.imageno.com/wz6gv1wuqajrpic.html
(maaf, saya tidak punya cukup reputasi untuk mengunggah gambar di sini: P)


2
OP menyatakan MSSQL. Anda memberi jawaban eksklusif untuk MySQL.
direformasi

-4

Anda bisa mencoba DELETE FROM <your table >;.

Server akan menunjukkan kepada Anda nama batasan dan tabel, dan menghapus tabel itu Anda dapat menghapus apa yang Anda butuhkan.


6
Baca frasa kedua pada pertanyaan. Dia tahu dia bisa melakukan itu, tetapi bukan itu yang dia inginkan
renanleandrof

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

referensi - memotong tabel dibatasi kunci asing

Bekerja untuk saya di MYSQL


1
Selain versi yang ditentukan, apakah ada yang salah dengan ini? Apakah akan direkomendasikan untuk menggunakannya, atau menghindarinya sama sekali?
Andy Ibanez

1
@AndyIbanez MySQL adalah produk yang sama sekali berbeda dari MSSQL, bukan versi MSSQL yang berbeda.
Dan Bechard

1
jawaban yang benar saya tidak tahu mengapa semua orang memberi negatif
sunil
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.