Tabelle kann nicht abgeschnitten werden, da auf sie durch eine FOREIGN KEY-Einschränkung verwiesen wird?


459

Kann ich mit MSSQL2005 eine Tabelle mit einer Fremdschlüsseleinschränkung abschneiden, wenn ich zuerst die untergeordnete Tabelle (die Tabelle mit dem Primärschlüssel der FK-Beziehung) abschneide?

Ich weiß, dass ich es auch kann

  • Verwenden Sie eine DELETEohne where-Klausel und dann RESEEDdie Identität (oder)
  • Entfernen Sie die FK, schneiden Sie die Tabelle ab und erstellen Sie die FK neu.

Ich dachte, solange ich die untergeordnete Tabelle vor der übergeordneten Tabelle abgeschnitten habe, wäre ich in Ordnung, ohne eine der oben genannten Optionen auszuführen, aber ich erhalte den folgenden Fehler:

Die Tabelle 'TableName' kann nicht abgeschnitten werden, da auf sie durch eine FOREIGN KEY-Einschränkung verwiesen wird.

Antworten:


379

Richtig; Sie können eine Tabelle mit einer FK-Einschränkung nicht abschneiden.

Normalerweise ist mein Prozess dafür:

  1. Löschen Sie die Einschränkungen
  2. Schneiden Sie die Tabelle ab
  3. Erstellen Sie die Einschränkungen neu.

(Natürlich alles in einer Transaktion.)

Dies gilt natürlich nur, wenn das Kind bereits abgeschnitten wurde. Ansonsten gehe ich einen anderen Weg, abhängig davon, wie meine Daten aussehen. (Zu viele Variablen, um hier darauf einzugehen.)

Das Originalplakat bestimmte, WARUM dies der Fall ist; Weitere Informationen finden Sie in dieser Antwort .


73
Ein "DELETE FROM" setzt keine automatisch inkrementierenden Spalten zurück. Ein Abschneiden tut es. Sie sind funktional nicht gleichwertig.
Robross0606

35
Abschneiden ist oft genau das, was Sie tun möchten, wenn Sie große Datenmengen löschen. Eine Million Zeilen abschneiden? Eine Billion? 1 ms ... also, @ M07, bitte sagen Sie nicht, dass "Löschen vom Ansatz sauberer ist", da dies nur aus der Ferne nicht genau ist.
CTB

1
Nach dem Löschen großer Datenmengen muss der Benutzer die Tabellen und Protokolldateien verkleinern, um den Speicherplatz zurückzugewinnen.
Muhammad Yousaf Sulahria

2
Die Magic Shrink-Schaltfläche (oder das Skript) wird in 99% der Fälle nicht empfohlen.
Tom Stickel

1
Und wie würden Sie das machen? Beispielanfragen?
Jeromej

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

Beachten Sie, dass dies wahrscheinlich nicht das ist, was Sie möchten, wenn Sie über Millionen von Datensätzen verfügen, da es sehr langsam ist.


Das war nützlich und schneller als das Deaktivieren und Aktivieren von Einschränkungen.
Sensei

Dies funktioniert nur für Tabellen mit weniger Daten. Stimmen
Sie

1
Dies ist
ideal,

3
Ich würde nicht vorschlagen, diesen Weg zu gehen, da Sie möglicherweise auch diesen Fehler erhalten: Die DELETE-Anweisung widersprach der REFERENCE-Einschränkung
sksallaj

Hat bei mir nicht funktioniert. Die DELETE-Anweisung steht immer noch im Widerspruch zur REFERENCE-Einschränkung.
Emirhosseini

192

Da TRUNCATE TABLEes sich um einen DDL-Befehl handelt , kann nicht überprüft werden, ob auf die Datensätze in der Tabelle von einem Datensatz in der untergeordneten Tabelle verwiesen wird.

Dies DELETEfunktioniert und TRUNCATE TABLEfunktioniert nicht: weil die Datenbank sicherstellen kann, dass sie nicht von einem anderen Datensatz referenziert wird.


92

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

Als gespeicherte Prozedur

https://github.com/reduardo7/TableTruncate

Hinweis dass dies wahrscheinlich nicht das ist, was Sie möchten, wenn Sie über Millionen von Datensätzen verfügen, da es sehr langsam ist.


3
Die Verwendung von reseed new value = 1 nach DELETE FROM würde alle von ID 2 anstelle von 1 beginnen. Von Technet ( technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx ) Wenn keine Zeilen vorhanden waren In die Tabelle eingefügt, seit sie erstellt wurde, oder alle Zeilen mithilfe der Anweisung TRUNCATE TABLE entfernt wurden. Die erste Zeile, die nach dem Ausführen von DBCC CHECKIDENT eingefügt wurde, verwendet new_reseed_value als Identität. Andernfalls verwendet die nächste eingefügte Zeile new_reseed_value + den aktuellen Inkrementwert.
Zoran P.

@ ZoranP. Bitte sehen Sie gespeicherte Prozedur Variante: github.com/reduardo7/TableTruncate
Eduardo Cuomo

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

1
@TicoFortes Beitrag aktualisiert. Bitte sehen Sie gespeicherte Prozedur Variante
Eduardo Cuomo

1
Dies ist kein guter Ansatz. Wie von der 700 anderen Version derselben Antwort auf diese Frage kommentiert. WENN sich Ihre Datenbank nicht im einfachen Wiederherstellungsmodus befindet, um die Transaktionsprotokollierung einzuschränken.
Pimbrouwers

68

Die oben bereitgestellte Lösung @denver_citizen hat bei mir nicht funktioniert, aber ich mochte den Geist davon, also habe ich einige Dinge geändert:

  • machte es zu einer gespeicherten Prozedur
  • Die Art und Weise, wie die Fremdschlüssel gefüllt und neu erstellt werden, wurde geändert
  • Das ursprüngliche Skript schneidet alle referenzierten Tabellen ab. Dies kann zu Fehlern bei der Verletzung von Fremdschlüsseln führen, wenn die referenzierte Tabelle andere Fremdschlüsselreferenzen enthält. Dieses Skript schneidet nur die als Parameter angegebene Tabelle ab. Es ist Sache des Benutzers, diese gespeicherte Prozedur für alle Tabellen in der richtigen Reihenfolge mehrmals aufzurufen

Zum Wohle der Öffentlichkeit ist hier das aktualisierte Skript:

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
Diese Antwort verdient mehr Stimmen! Tatsächlich würde ich dir gerne ein Bier kaufen, wenn ich könnte, Peter :)
nsimeonov

Dies war heute eine große Hilfe für mich, um schnell einige große Tabellen ihrer Daten zum Testen zu löschen. Vielen Dank für die Qualitätsarbeit daran.
Craig Selbert

4
Vielen Dank für diesen Code. Beachten Sie jedoch, dass Sie eine zusätzliche Logik hinzufügen sollten, um deaktivierte FKs zu überprüfen. Andernfalls aktivieren Sie derzeit deaktivierte Einschränkungen.
Andre Figueiredo

2
Ich habe eine Version mit den Vorschlägen von @AndreFigueiredo gemacht. Ich stelle es auf Gitlab: gitlab.com/ranolfi/truncate-referenced-table . Fühlen Sie sich frei, den Code in Ihre Antwort aufzunehmen.
März 2377

1
Das ist großartig, aber beachten Sie, dass es nicht funktioniert, wenn Ihre Tabellen nicht im Standardschema (dbo) enthalten sind.
Sidewinder94

19

Verwenden Sie den folgenden Befehl, nachdem Sie alle Zeilen in dieser Tabelle mit der Anweisung delete gelöscht haben

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

BEARBEITEN: Syntax für SQL Server korrigiert


9
TRUNCATEvermeidet das Protokoll und ist erheblich schneller als DELETEbei großen Tabellen. Insofern ist dies keine echte äquivalente Lösung.
Siride

1
Wie unterscheidet sich diese Antwort von der , die ein Jahr zuvor gegeben wurde?
Ofer Zelig

17

Nun, da ich keine Beispiele für die sehr einfache Lösung gefunden habe, die ich verwendet habe:

  1. Fremdschlüssel löschen;
  2. Tabelle abschneiden
  3. Fremdschlüssel neu erstellen

Hier kommt's:

1) Suchen Sie den Fremdschlüsselnamen, der den Fehler verursacht (zum Beispiel: FK_PROBLEM_REASON, mit Feld ID , aus Tabelle TABLE_OWNING_CONSTRAINT). 2) Entfernen Sie diesen Schlüssel aus der Tabelle:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Gesuchte Tabelle abschneiden

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Fügen Sie den Schlüssel erneut zu dieser ersten Tabelle hinzu:

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

Das ist es.


Dies funktioniert nicht, wenn Sie mehrere Tabellen mit Fremdschlüsselreferenzen haben. Sie müssten viele Fremdschlüsseleinschränkungen in der gesamten Datenbank entfernen.
jbright

13

Hier ist ein Skript, das ich geschrieben habe, um den Prozess zu automatisieren. Ich hoffe, es hilft.

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
Achtung. Ich würde Ihrem Skript auch referenzielle Aktionen für die Schlüssel hinzufügen, sonst verlieren Sie die Kaskadeneinstellungen.
Alphadogg

1
Dies funktioniert bei mir nicht, aber ich mochte den Geist davon, also habe ich ein paar Dinge geändert: Als gespeicherte Prozedur wurde die Art und Weise geändert, in der die Fremdschlüssel gefüllt und neu erstellt werden. Das ursprüngliche Skript schneidet alle referenzierten Tabellen ab. Dies kann falsch sein, wenn auf die referenziert wird Tabelle kann nicht abgeschnitten werden, da sie auch Fremdschlüsselreferenzen enthält. In dieser Version wird nur die als Parameter angegebene Tabelle abgeschnitten. Alle Tabellen, auf die verwiesen wird, sollten manuell abgeschnitten werden, bevor dieses Skript aufgerufen wird. Ich habe die aktualisierte Lösung in diesem Thread hier veröffentlicht. Stackoverflow.com/a/13249209/157591
Peter Szanto

1
@alphadogg Gibt es eine Möglichkeit, diese referenziellen Aktionen zu finden? Ich habe im Internet gestöbert und kann sie anscheinend nicht finden. Ich kann es als formelle Frage posten, wenn Sie möchten.
Michael - Wo ist Clay Shirky

1
Hinweis für zukünftige Besucher: Es ist in der sys.foreign_keysTabelle. ( Referenz )
Michael - Wo ist Clay Shirky

@ Michael: Sie können auch INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/library/ms179987.aspx )
alphadogg

13

Sie können diesen Schritt ausführen, indem reseeding tableSie die Daten der Tabelle löschen können.

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

Wenn ein Fehler auftritt, müssen Sie die Primärtabelle erneut setzen.


1
Beachten Sie, dass das Transaktionsprotokoll, obwohl dies gut funktioniert, um die Anzahl der Datensätze in der Tabelle im Vergleich zu "Tabelle abschneiden" erhöht wird, die nur einen Datensatz in das Transaktionsprotokoll aufnehmen. Für die meisten Tabellen keine große Sache, aber wenn es mehr als Millionen Zeilen gibt, könnte dies ein Problem sein.
David

9
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;

8
Diese Frage bezieht sich auf MS SQL Server, der keine FOREIGN_KEY_CHECKS-Einstellung hat
Elezar

1
Ich denke, dies würde von MySQL funktionieren, aber nicht von MS SQL Server
Cocowalla

8

Wenn ich das richtig verstehe, möchten Sie eine saubere Umgebung für die Datenbank einrichten, die Integrationstests umfasst.

Mein Ansatz hier wäre, das gesamte Schema zu löschen und es später neu zu erstellen.

Gründe dafür:

  1. Sie haben wahrscheinlich bereits ein Skript zum Erstellen eines Schemas. Die Wiederverwendung zur Testisolierung ist einfach.
  2. Das Erstellen eines Schemas ist ziemlich schnell.
  3. Mit diesem Ansatz ist es ziemlich einfach, Ihr Skript so einzurichten, dass jedes Gerät ein NEUES Schema (mit einem temporären Namen) erstellt. Anschließend können Sie Test-Geräte parallel ausführen, wodurch der langsamste Teil Ihrer Testsuite viel schneller wird .

1
Ich möchte das gesamte Schema "abschneiden" und nicht löschen. Ich möchte dies in der Setup-Methode für Integrationstests tun. Das Aufrufen des DB-Erstellungsskripts aus Integrationstests heraus ist ... nicht die erste Lösung, zu der ich gehen werde.
Ripper234

7

An anderer Stelle im Web gefunden

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
Sollte wahrscheinlich 'ALTER TABLE sein? MIT CHECK CHECK CONSTRAINT ALL '.
Andriy M

20
-1: Nur bestätigt, dass dies mit dem in der Frage gestellten Befehl zum Abschneiden überhaupt nicht funktioniert. Siehe stackoverflow.com/questions/3843806/…
Lynn Crumbling

7

Sie können eine Tabelle nicht abschneiden, wenn Sie die Einschränkungen nicht löschen. Eine Deaktivierung funktioniert auch nicht. Sie müssen alles fallen lassen. Ich habe ein Skript erstellt, das alle Einschränkungen löscht und dann neu erstellt.

Stellen Sie sicher, dass Sie es in eine Transaktion einwickeln;)

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

Die Antworten von @denver_citizen und @Peter Szanto haben bei mir nicht ganz funktioniert, aber ich habe sie geändert, um Folgendes zu berücksichtigen:

  1. Zusammengesetzte Schlüssel
  2. Aktionen zum Löschen und Aktualisieren
  3. Überprüfen des Index beim erneuten Hinzufügen
  4. Andere Schemata als dbo
  5. Mehrere Tabellen gleichzeitig
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

kürzen hat bei mir nicht funktioniert, löschen + reseed ist der beste Ausweg. Falls es einige von Ihnen gibt, die eine große Anzahl von Tabellen durchlaufen müssen, um Löschen + erneutes Einfügen durchzuführen, können Probleme mit einigen Tabellen auftreten, die keine Identitätsspalte haben. Der folgende Code überprüft, ob eine Identitätsspalte vorhanden ist, bevor Sie versuchen neu besäen

    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

Ich habe die folgenden Methoden geschrieben und versucht, sie zu parametrisieren, damit Sie sie in einem Query documentOr Make a nützlich SPmachen können .

A) Löschen

Wenn Ihre Tabelle nicht über Millionen von Datensätzen verfügt, funktioniert dies gut und es gibt keine Änderungsbefehle :

---------------------------------------------------------------
------------------- 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)
  • In meiner obigen Antwort basiert die Methode zur Lösung des in der Frage genannten Problems auf der Antwort @ s15199d .

B) Abschneiden

Wenn Ihre Tabelle Millionen von Datensätzen enthält oder Sie kein Problem mit dem Befehl Ändern in Ihren Codes haben, verwenden Sie diesen:

--   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
  • In meiner obigen Antwort basiert die Methode zur Lösung des in der Frage genannten Problems auf der Antwort von @LauroWolffValenteSobrinho .

  • Wenn Sie mehr als eine Einschränkung haben, sollten Sie die Codes wie ich an die obige Abfrage anhängen

  • Sie können auch die obige @ SerjSagan- Antwort auf Codebasis ändern , um die Einschränkung zu deaktivieren


3

Es ist meine Lösung für dieses Problem. Ich habe es verwendet, um PK zu ändern, aber ich habe die gleiche Idee. Hoffe das wird nützlich sein)

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

Für MS SQLzumindest die neueren Versionen, können Sie einfach das Constraints mit Code wie folgt deaktivieren:

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

Ich denke, wir haben oben festgestellt, dass dies nicht funktioniert? Vielleicht für neuere Versionen?
Coops

2
Fwiw, dies funktioniert nicht in der OP-Version (2005) und auch nicht in seinem Nachfolger (MSSQL2008).
CB

3

Das Folgende funktioniert für mich auch mit FK-Einschränkungen und kombiniert die folgenden Antworten, um nur die angegebenen Tabellen zu löschen :


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;

Hinweis:

Ich denke, es hilft immer noch, die Tabellen in der Reihenfolge zu deklarieren, in der sie gelöscht werden sollen (dh Abhängigkeiten zuerst töten). Wie in dieser Antwort zu sehen ist , können Sie anstelle von schleifenspezifischen Namen alle Tabellen durch ersetzen

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

Ich habe es nicht wirklich mit anderen Skripten versucht, da alle angegeben haben, dass sie nicht funktionieren, wenn Sie Fremdschlüssel haben. Also habe ich es versucht und dieses hat den Trick für mich gemacht.
Vivendi

1
DELETE ist nicht dasselbe wie TRUNCATE. Dadurch werden Ihre Transaktionsprotokolle gefüllt.
Dan Bechard

@ Dan, wahrscheinlich ein guter Punkt; Wie
gesagt,

@drzaus Es funktioniert gut für kleine / mittlere Tabellen, aber ich habe einen Produktions-SQL Server offline geschaltet, weil ein Löschbefehl das Transaktionsprotokoll füllte, das die Festplatte füllte. Stellen Sie mindestens sicher, dass Ihre Transaktionsprotokolle eine maximale Größe haben, bevor Sie dies in einer großen Tabelle versuchen.
Dan Bechard

2

Wenn keine dieser Antworten wie in meinem Fall funktioniert hat, gehen Sie wie folgt vor:

  1. Einschränkungen löschen
  2. Stellen Sie alle Werte so ein, dass Nullen zulässig sind
  3. Tabelle abschneiden
  4. Fügen Sie Einschränkungen hinzu, die gelöscht wurden.

Viel Glück!


Gibt es ein SQL-Beispiel dazu?
Kiquenet

2

Löschen und dann das automatische Inkrement zurücksetzen:

delete from tablename;

dann

ALTER TABLE tablename AUTO_INCREMENT = 1;

Danke, das hat gut funktioniert.
Mr. Polywhirl

1

Die einzige Möglichkeit besteht darin, Fremdschlüssel vor dem Abschneiden zu löschen. Nach dem Abschneiden der Daten müssen Sie die Indizes neu erstellen.

Das folgende Skript generiert die erforderliche SQL zum Löschen aller Fremdschlüsseleinschränkungen.

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

Als Nächstes generiert das folgende Skript das erforderliche SQL zum erneuten Erstellen von Fremdschlüsseln.

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

Führen Sie das generierte Skript aus, um alle Fremdschlüssel zu löschen, Tabellen abzuschneiden, und führen Sie dann das generierte Skript aus, um alle Fremdschlüssel neu zu erstellen.

Die Anfragen werden von hier übernommen .


0

In SSMS hatte ich ein geöffnetes Diagramm mit dem Schlüssel. Nachdem ich den Schlüssel gelöscht und die Datei abgeschnitten hatte, konzentrierte ich mich auf das Diagramm und erstellte ein Update, indem ich ein Identitätsfeld löschte und dann wiederherstellte. Beim Speichern des Diagramms wurde ein Dialogfeld zum Speichern angezeigt. Anschließend wurde im Dialogfeld "Während Sie arbeiteten, wurden Änderungen an der Datenbank vorgenommen" durch Klicken auf "Ja" der Schlüssel wiederhergestellt und aus der gesperrten Kopie im Diagramm wiederhergestellt.


0

Wenn Sie dies in irgendeiner Häufigkeit tun, zum Teufel sogar nach einem Zeitplan, würde ich absolut niemals eine DML-Anweisung verwenden. Die Kosten für das Schreiben in das Transaktionsprotokoll sind einfach zu hoch und das Einstellen der gesamten DatenbankSIMPLE ist lächerlich Wiederherstellungsmodus zu versetzen, um eine Tabelle abzuschneiden.

Der beste Weg ist leider der harte oder mühsame Weg. Das ist:

  • Einschränkungen löschen
  • Tabelle abschneiden
  • Erstellen Sie Einschränkungen neu

Mein Prozess dazu umfasst die folgenden Schritte:

  1. Klicken Sie in SSMS mit der rechten Maustaste auf die betreffende Tabelle und wählen Sie Abhängigkeiten
  2. Beachten Sie die Tabellen, auf die verwiesen wird (falls vorhanden).
  3. Erweitern Sie im Objekt-Explorer die Schlüssel Knoten und notieren Sie sich die Fremdschlüssel (falls vorhanden).
  4. Starten Sie die Skripterstellung (Löschen / Abschneiden / Neuerstellen)

Skripte dieser Art sollten innerhalb eines begin tranand- commit tranBlocks erstellt werden.


-3

Ich habe festgestellt , dass nur Sie TRUNCATE Tabelle auf einer übergeordneten Tabelle mit Fremdschlüssel - Constraints auf ein Kind so lange verwenden können , wie Sie die Einschränkungen für die SPERREN Kind Tabelle zuerst. Z.B

Der Fremdschlüssel CONSTRAINT child_par_ref in der untergeordneten Tabelle verweist auf 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
Dies ist keine gültige SQL Server-Syntax für ALTER TABLE. Es gibt kein {ENABLE | DISABLE} CONSTRAINT. Siehe: msdn.microsoft.com/en-us/library/ms190273.aspx
jason_ruz

-3

Der einfachste Weg:
1 - Geben Sie phpmyadmin ein.
2 - Klicken Sie auf den Tabellennamen in der linken Spalte.
3 - Klicken Sie auf Operation (oberes Menü).
4 - Klicken Sie auf "Tabelle leeren (TRUNCATE).
5 - Deaktivieren Sie das Kontrollkästchen" Fremdschlüsselprüfungen aktivieren ".
6 - Fertig !

Link zum Bild-Tutorial
Tutorial: http://www.imageno.com/wz6gv1wuqajrpic.html
(Entschuldigung, ich habe nicht genug Ruf, um Bilder hier hochzuladen: P)


2
OP erklärte MSSQL. Sie haben eine Antwort exklusiv für MySQL gegeben.
Reformiert am

-4

Du könntest es versuchen DELETE FROM <your table >;.

Der Server zeigt Ihnen den Namen der Einschränkung und die Tabelle an. Wenn Sie diese Tabelle löschen, können Sie löschen, was Sie benötigen.


6
Lesen Sie seinen zweiten Satz zu dieser Frage. Er weiß, dass er das kann, aber das will er nicht
Renanleandrof

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

referenz - Fremdschlüssel-Zwischentabelle abschneiden

Ich arbeite für mich in MYSQL


1
Gibt es außer der angegebenen Version noch etwas, das daran falsch ist? Wäre es empfehlenswert, es zu verwenden oder es ganz zu vermeiden?
Andy Ibanez

1
@AndyIbanez MySQL ist ein völlig anderes Produkt als MSSQL, keine andere Version von MSSQL.
Dan Bechard

1
seine richtige Antwort Ich weiß nicht, warum jeder negativ gibt
sunil
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.