Impossibile troncare la tabella perché a cui fa riferimento un vincolo FOREIGN KEY?


459

Utilizzando MSSQL2005, posso troncare una tabella con un vincolo di chiave esterna se prima troncare la tabella figlio (la tabella con la chiave primaria della relazione FK)?

So che posso farlo

  • Utilizzare una DELETEclausola senza un dove e quindi RESEEDl'identità (o)
  • Rimuovere l'FK, troncare la tabella e ricreare l'FK.

Ho pensato che finché avessi troncato la tabella figlio prima del genitore, starei bene senza fare nessuna delle opzioni sopra, ma sto ottenendo questo errore:

Impossibile troncare la tabella 'TableName' perché viene referenziata da un vincolo FOREIGN KEY.

Risposte:


379

Corretta; non puoi troncare una tabella che ha un vincolo FK su di essa.

In genere il mio processo per questo è:

  1. Elimina i vincoli
  2. Troncare il tavolo
  3. Ricreare i vincoli.

(Tutto in una transazione, ovviamente.)

Naturalmente, questo vale solo se il bambino è già stato troncato. Altrimenti seguo una strada diversa, completamente dipendente dall'aspetto dei miei dati. (Troppe variabili per entrare qui.)

Il poster originale ha determinato PERCHÉ questo è il caso; vedi questa risposta per maggiori dettagli.


73
Un "ELIMINA DA" non reimposta le colonne a incremento automatico. Un troncato fa. Non sono funzionalmente equivalenti.
robross0606,

35
Troncare è spesso esattamente ciò che si desidera fare se si eliminano enormi quantità di dati. Troncare un milione di righe? Un miliardo? 1 ms ... quindi, @ M07, per favore non dire che "elimina dall'approccio è più pulito", perché non è accurato da remoto.
ctb

1
Dopo aver eliminato dati di grandi dimensioni, l'utente deve ridurre le tabelle e i file di registro anche per recuperare lo spazio su disco.
Muhammad Yousaf Sulahria,

2
Il pulsante Magic Shrink (o lo script) non è consigliato il 99% delle volte.
Tom Stickel,

1
E come lo faresti? Richieste di esempio?
Jeromej,

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

Nota che questo non è probabilmente quello che vorresti se avessi milioni + di record, poiché è molto lento.


Era un modo utile e più veloce di disabilitare e abilitare il vincolo.
sensei,

Funzionerà solo per tabelle con meno dati. Concordo con @Pure
Dhanuka777 il

1
Questo è ottimo per quando hai finito di testare uno schema
ohmusama

3
Non consiglierei di seguire questa strada, poiché potresti anche ottenere questo errore: L'istruzione DELETE è in conflitto con il vincolo REFERENCE
sksallaj

Non ha funzionato per me. Ancora ottenere l'istruzione DELETE in conflitto con il vincolo REFERENCE.
emirhosseini,

192

Poiché TRUNCATE TABLEè un comando DDL , non può verificare se i record nella tabella fanno riferimento a un record nella tabella figlio.

Questo è il motivo per cui DELETEfunziona e TRUNCATE TABLEnon funziona: perché il database è in grado di assicurarsi che non venga referenziato da un altro record.


92

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

Come procedura memorizzata

https://github.com/reduardo7/TableTruncate

Nota che questo non è probabilmente quello che vorresti se avessi milioni + di record, poiché è molto lento.


3
usando il nuovo valore resed = 1 dopo DELETE FROM inizierebbe tutto da ID 2, anziché 1. Da Technet ( technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx ) Se non è stata trovata alcuna riga inserita nella tabella da quando è stata creata, o tutte le righe sono state rimosse usando l'istruzione TRUNCATE TABLE, la prima riga inserita dopo aver eseguito DBCC CHECKIDENT utilizza new_reseed_value come identità. In caso contrario, la riga successiva inserita utilizza new_reseed_value + il valore di incremento corrente.
Zoran P.

@ZoranP. si prega di consultare la variante della procedura memorizzata: github.com/reduardo7/TableTruncate
Eduardo Cuomo,

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

1
@TicoFortes Post aggiornato. Si prega di vedere la variante della procedura memorizzata
Eduardo Cuomo,

1
Questo non è un buon approccio. Come commentato dall'altra 700 versione di questa stessa risposta a questa domanda. A MENO CHE il database non sia in modalità di ripristino semplice, per limitare la registrazione delle transazioni.
pimbrouwers,

68

La soluzione @denver_citizen fornita sopra non ha funzionato per me, ma mi è piaciuto lo spirito, quindi ho modificato alcune cose:

  • ha reso una procedura memorizzata
  • cambiato il modo in cui le chiavi esterne vengono popolate e ricreate
  • lo script originale tronca tutte le tabelle referenziate, ciò può causare errori di violazione della chiave esterna quando la tabella referenziata ha altri riferimenti a chiave esterna. Questo script tronca solo la tabella specificata come parametro. Spetta all'utente, chiamare questa procedura memorizzata più volte su tutte le tabelle nell'ordine corretto

A beneficio del pubblico ecco lo script aggiornato:

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
Questa risposta merita più voti! In effetti, ti darei volentieri una birra se potessi, Peter :)
nsimeonov,

Mi è stato di grande aiuto oggi per cancellare rapidamente alcune grandi tabelle dei loro dati per i test, grazie per il lavoro di qualità su questo.
Craig Selbert,

4
Grazie per questo pezzo di codice. Ma attenzione, è necessario aggiungere una logica aggiuntiva per controllare gli FK disabilitati. Altrimenti, abiliterai i vincoli attualmente disabilitati.
Andre Figueiredo,

2
Ho realizzato una versione con i suggerimenti di @AndreFigueiredo. Lo sto mettendo su Gitlab: gitlab.com/ranolfi/truncate-referenced-table . Sentiti libero di incorporare il codice nella tua risposta.
Marc.2377,

1
Questo è fantastico, ma tieni presente che non funzionerà se le tue tabelle non sono nello schema predefinito (dbo).
Sidewinder94,

19

utilizzare il comando seguente dopo l'eliminazione di tutte le righe in quella tabella utilizzando l'istruzione delete

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

EDIT: sintassi corretta per SQL Server


9
TRUNCATEevita il registro ed è notevolmente più veloce rispetto DELETEalle tabelle di grandi dimensioni. Pertanto, questa non è una vera soluzione equivalente.
siride,

1
In che modo questa risposta è diversa da quella che era stata data un anno prima?
Ofer Zelig,

17

Bene, dal momento che non ho trovato esempi della soluzione molto semplice che ho usato, che è:

  1. Rilasciare chiave esterna;
  2. Tronca tabella
  3. Ricrea la chiave esterna

Eccolo:

1) Trova il nome della chiave esterna che causa l'errore (ad esempio: FK_PROBLEM_REASON, con campo ID, dalla tabella TABLE_OWNING_CONSTRAINT) 2) Rimuovi quella chiave dalla tabella:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Tronca la tabella desiderata

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Aggiungi nuovamente la chiave a quella prima tabella:

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

Questo è tutto.


Questo non funziona se hai più tabelle con riferimenti a chiave esterna. Dovresti rimuovere molte restrizioni di chiave esterna in tutto il database.
jbright,

13

Ecco uno script che ho scritto per automatizzare il processo. Spero possa essere d'aiuto.

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
Stai attento. Aggiungerei anche azioni referenziali sui tasti del tuo script o perderai le impostazioni a cascata.
alphadogg,

1
questo non funziona per me, ma mi è piaciuto lo spirito, quindi ho modificato alcune cose: reso una procedura memorizzata ha cambiato il modo in cui vengono popolate le chiavi esterne e ricreato lo script originale tronca tutte le tabelle di riferimento, questo può essere sbagliato quando il riferimento la tabella non può essere troncata perché ha anche riferimenti a chiave esterna. In questa versione verrà troncata solo la tabella specificata come parametro, tutta la tabella referenziata dovrebbe essere troncata manualmente prima di chiamare questo script Ho pubblicato la risoluzione aggiornata su questa discussione qui stackoverflow.com/a/13249209/157591
Peter Szanto

1
@alphadogg C'è un modo per trovare quelle azioni referenziali? Ho cercato su Internet e non riesco a trovarli. Posso pubblicarlo come una domanda formale, se preferisci.
Michael - Dov'è Clay Shirky

1
Nota per i futuri visitatori: è nella sys.foreign_keystabella. ( Riferimento )
Michael - Dov'è Clay Shirky

@Michael: puoi anche utilizzare INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/library/ms179987.aspx )
alphadogg,

13

puoi seguire questo passaggio, reseeding tablepuoi cancellare i dati della tabella.

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

se si verifica un errore, è necessario ridimensionare la tabella principale.


1
Tieni presente che anche se funziona correttamente, il registro delle transazioni aumenterà del numero di record nella tabella rispetto a "tabella troncata" che inserisce solo un record nel registro delle transazioni. Non è un grosso problema per la maggior parte delle tabelle, ma se ci sono milioni + righe potrebbe essere un problema.
David

9
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;

8
Questa domanda riguarda MS SQL Server, che non ha un'impostazione FOREIGN_KEY_CHECKS
Elezar

1
Penso che funzionerebbe da MySQL, ma non da MS SQL Server
Cocowalla il

8

Se ho capito bene, quello che vuoi fare è avere un ambiente pulito da impostare per DB che includa test di integrazione.

Il mio approccio qui sarebbe quello di eliminare l'intero schema e ricrearlo in seguito.

Motivi:

  1. Probabilmente hai già uno script "crea schema". Riutilizzarlo per l'isolamento del test è semplice.
  2. La creazione di uno schema è piuttosto rapida.
  3. Con questo approccio, è abbastanza facile impostare lo script in modo che ogni dispositivo crei un NUOVO schema (con un nome temporaneo), quindi puoi iniziare a eseguire test-fixture in parallelo, rendendo la parte più lenta della tua suite di test molto più velocemente .

1
Vorrei "troncare" tutto lo schema, non lasciarlo cadere. Mi piacerebbe farlo nel metodo Setup dei test di integrazione. Chiamare lo script di creazione del DB dai test di integrazione non è ... la prima soluzione a cui andrò.
ripper234,

7

Trovato altrove sul 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
Probabilmente dovrebbe essere 'ALTER TABLE? CON CONTROLLA CONTROLLA VINCERE TUTTO '.
Andriy M,

20
-1: Ho appena confermato che non funziona affatto con il comando troncato come richiesto dalla domanda. Vedi stackoverflow.com/questions/3843806/…
Lynn Crumbling,

7

Non è possibile troncare una tabella se non si eliminano i vincoli. Anche una disabilitazione non funziona. devi eliminare tutto. ho realizzato una sceneggiatura che elimina tutti i vincoli e poi li ricrea.

Assicurati di inserirlo in una transazione;)

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

Le risposte di @denver_citizen e @Peter Szanto non hanno funzionato abbastanza per me, ma le ho modificate per tenere conto di:

  1. Tasti compositi
  2. Azioni Elimina e Aggiorna
  3. Verifica dell'indice quando si aggiunge nuovamente
  4. Schemi diversi da dbo
  5. Più tabelle contemporaneamente
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

troncare non ha funzionato per me, eliminare + reseed è la migliore via d'uscita. Nel caso ci siano alcuni di voi là fuori che hanno bisogno di iterare su un numero enorme di tabelle per eseguire delete + reseed, potreste incorrere in problemi con alcune tabelle che non hanno una colonna di identità, il seguente codice controlla se esiste la colonna di identità prima di provare resed

    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

Scrivo i seguenti modi e ho provato a parametrizzarli, in modo da poterli eseguire in un Query documento rendere SPfacilmente utile con loro .

A) Elimina

Se la tua tabella non ha milioni di record, questo funziona bene e non ha alcun comando 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)
  • Nella mia risposta sopra il metodo per risolvere il problema menzionato nella domanda si basa sulla risposta @ s15199d .

B) Tronca

Se la tua tabella ha milioni di record o non hai nessun problema con il comando Alter nei tuoi codici, usa questo:

--   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
  • Nella mia risposta sopra il metodo per risolvere il problema menzionato nella domanda si basa sulla risposta @LauroWolffValenteSobrinho .

  • Se hai più di una VINCITA, allora dovresti aggiungere i suoi codici come me alla query sopra

  • Inoltre è possibile modificare la risposta @SerjSagan di base di codice sopra per disabilitare un abilitazione del vincolo


3

È la mia soluzione a questo problema. L'ho usato per modificare PK, ma idea lo stesso. Spero che questo sia utile)

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

Per MS SQL, almeno le versioni più recenti, puoi semplicemente disabilitare i vincoli con codice come questo:

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

Penso che abbiamo stabilito sopra che questo non funziona? Forse lo fa per le versioni più recenti?
Coops

2
In seguito, questo non funziona nella versione dell'OP (2005) e non funziona anche nel suo successore (MSSQL2008).
CB

3

Quanto segue funziona per me anche con vincoli FK e combina le seguenti risposte per eliminare solo le tabelle specificate :


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;

Nota:

Penso che aiuti ancora a dichiarare le tabelle nell'ordine in cui vuoi che vengano eliminate (ovvero uccidi prima le dipendenze). Come visto in questa risposta , invece di ripetere il ciclo di nomi specifici, è possibile sostituire tutte le tabelle

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

Non ho davvero provato ad altri script poiché tutti hanno dichiarato che non funzionano quando si hanno le chiavi esterne. Quindi ho provato questo e questo ha fatto il trucco per me.
Vivendi,

1
DELETE non è lo stesso di TRUNCATE. Questo riempirà i registri delle transazioni.
Dan Bechard

@ Dan, probabilmente un buon punto; come ho già detto, ho appena combinato le altre risposte qui intorno ...
drzaus,

@drzaus Funzionerà benissimo per le tabelle medio / piccole, ma ho avuto un server SQL di produzione non in linea a causa di un comando di eliminazione che riempie il registro delle transazioni, che ha riempito il disco rigido. Per lo meno, assicurati che i registri delle transazioni abbiano una dimensione massima prima di provare su una tabella di grandi dimensioni.
Dan Bechard,

2

Se nessuna di queste risposte ha funzionato come nel mio caso, procedere come segue:

  1. Vincoli di caduta
  2. Impostare tutti i valori per consentire valori null
  3. Tronca tabella
  4. Aggiungi vincoli che sono stati eliminati.

In bocca al lupo!


qualche campione sql a riguardo?
Kiquenet,

2

Elimina quindi reimposta l'incremento automatico:

delete from tablename;

poi

ALTER TABLE tablename AUTO_INCREMENT = 1;

Grazie, ha funzionato bene.
Mr. Polywhirl,

1

L'unico modo è rilasciare le chiavi esterne prima di eseguire il troncamento. E dopo aver troncato i dati, è necessario ricreare gli indici.

Lo script seguente genera l'SQL richiesto per eliminare tutti i vincoli di chiave esterna.

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

Successivamente, il seguente script genera l'SQL richiesto per ricreare le chiavi esterne.

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

Eseguire lo script generato per eliminare tutte le chiavi esterne, troncare le tabelle e quindi eseguire lo script generato per ricreare tutte le chiavi esterne.

Le domande sono prese da qui .


0

In SSMS avevo il diagramma aperto che mostrava la chiave. Dopo aver eliminato la chiave e troncato il file, ho aggiornato, quindi mi sono concentrato nuovamente sul diagramma e ho creato un aggiornamento deselezionando e ripristinando una casella Identità. Salvando il diagramma si apriva una finestra di dialogo Salva, che una finestra di dialogo "Sono state apportate modifiche al database mentre si stava lavorando", facendo clic su Sì ripristinato la chiave, ripristinandola dalla copia bloccata nel diagramma.


0

Se lo stai facendo a qualsiasi tipo di frequenza, diamine anche secondo un programma, non userei assolutamente, inequivocabilmente, un'istruzione DML. Il costo per scrivere nel registro delle transazioni è troppo alto e impostare l'intero databaseSIMPLE modalità di ripristino per troncare una tabella è ridicolo.

Il modo migliore, purtroppo, è il modo difficile o laborioso. Quell'essere:

  • Vincoli di caduta
  • Tronca tabella
  • Ricreare i vincoli

Il mio processo per farlo prevede i seguenti passaggi:

  1. In SSMS fare clic con il tasto destro del mouse sulla tabella in questione e selezionare Visualizza dipendenze
  2. Prendi nota delle tabelle referenziate (se presenti)
  3. Torna in Esplora oggetti, espandi il nodo Chiavi e prendi nota delle chiavi esterne (se presenti)
  4. Inizia lo scripting (trascina / tronca / ricrea)

Script di questa natura dovrebbero essere eseguiti all'interno di un blocco begin trane commit tran.


-3

Ho appena scoperto che è possibile utilizzare la tabella TRUNCATE su una tabella padre con vincoli di chiave esterna su un bambino purché si DISATTIVANO prima i vincoli sulla tabella figlio . Per esempio

Chiave esterna CONSTRAINT child_par_ref nella tabella figlio, riferimenti 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
Questa non è una sintassi valida di SQL Server per ALTER TABLE. Non esiste {ENABLE | DISABLE} VINCOLO. Vedi: msdn.microsoft.com/en-us/library/ms190273.aspx
jason_ruz

-3

Il modo più semplice:
1 - Inserisci in phpmyadmin
2 - Fai clic sul nome della tabella nella colonna di sinistra
3 - Fai clic su Operazione (menu in alto)
4 - Fai clic su "Svuota la tabella (TRUNCATE)
5 - Disattiva la casella" Abilita controlli chiave esterna "
6 - Fine !

Link al tutorial di immagini
Tutorial: http://www.imageno.com/wz6gv1wuqajrpic.html
(mi dispiace, non ho abbastanza reputazione per caricare immagini qui: P)


2
OP ha dichiarato MSSQL. Hai dato una risposta esclusiva a MySQL.
riformato l'

-4

Potresti provare DELETE FROM <your table >;.

Il server ti mostrerà il nome della restrizione e la tabella, ed eliminando quella tabella puoi eliminare ciò di cui hai bisogno.


6
Leggi la sua seconda frase sulla domanda. Sa di poterlo fare, ma non è quello che vuole
renanleandrof

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

riferimento - tronca la tabella vincolata con chiave esterna

Lavorando per me in MYSQL


1
Oltre alla versione specificata, c'è qualcos'altro che non va in questo? Si consiglia di usarlo o evitarlo del tutto?
Andy Ibanez,

1
@AndyIbanez MySQL è un prodotto completamente diverso da MSSQL, non una versione diversa di MSSQL.
Dan Bechard,

1
la sua risposta corretta Non so perché tutti danno negativo
sunil
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.