Come si troncano tutte le tabelle in un database usando TSQL?


204

Ho un ambiente di test per un database che voglio ricaricare con nuovi dati all'inizio di un ciclo di test. Non mi interessa ricostruire l'intero database, semplicemente "reimpostare" i dati.

Qual è il modo migliore per rimuovere tutti i dati da tutte le tabelle usando TSQL? Esistono procedure, viste, ecc. Memorizzate nel sistema che possono essere utilizzate? Non voglio creare e mantenere manualmente le istruzioni di tabella troncata per ogni tabella, preferirei che fosse dinamico.

Risposte:


188

Per SQL 2005,

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

Associare più collegamenti per il 2000 e il 2005/2008 .


62
Non è possibile troncare le tabelle che hanno chiavi esterne, quindi funzionerà solo se non ci sono vincoli di chiave esterna tra le tabelle (o se sono state disabilitate).
marcj,

1
d'accordo..ho pensato da quando ha specificamente chiesto di troncare i tavoli, ha già risolto il problema con le chiavi esterne ..
Gulzar Nazim

@ gulzar- sorta di- ho pubblicato una domanda a parte su come gestire gli FK ma la tua risposta è meritevole.
Ray

11
@ Sam: No, non lo farà! I dati nelle tabelle sono irrilevanti. Finché esiste un vincolo di chiave esterna che fa riferimento alla tabella (anche disabilitata) non è possibile troncarla.
TToni,

3
'EXEC sp_MSForEachTable' DROP TABLE? ' Funziona anche bene :) (deliziando tutte le tabelle dal database)
kuncevic.dev

419

Quando si ha a che fare con l'eliminazione di dati da tabelle che hanno relazioni di chiave esterna - che è fondamentalmente il caso di qualsiasi database progettato correttamente - possiamo disabilitare tutti i vincoli, eliminare tutti i dati e quindi riattivare i vincoli

-- disable all constraints
EXEC sp_MSForEachTable "ALTER TABLE ? NOCHECK CONSTRAINT all"

-- delete data in all tables
EXEC sp_MSForEachTable "DELETE FROM ?"

-- enable all constraints
exec sp_MSForEachTable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

Maggiori informazioni sulla disabilitazione di vincoli e trigger qui

se alcune delle tabelle hanno colonne di identità, potremmo volerle ridimensionare

EXEC sp_MSForEachTable "DBCC CHECKIDENT ( '?', RESEED, 0)"

Si noti che il comportamento di RESEED differisce tra una tabella nuova di zecca e una che aveva precedentemente inserito alcuni dati da BOL :

DBCC CHECKIDENT ('table_name', RESEED, newReseedValue)

Il valore dell'identità corrente è impostato su newReseedValue. Se nessuna riga è stata inserita nella tabella da quando è stata creata, la prima riga inserita dopo l'esecuzione di DBCC CHECKIDENT utilizzerà newReseedValue come identità. In caso contrario, la riga successiva inserita utilizzerà newReseedValue + 1. Se il valore di newReseedValue è inferiore al valore massimo nella colonna identità, verrà generato il messaggio di errore 2627 sui riferimenti successivi alla tabella.

Grazie a Robert per aver sottolineato il fatto che la disabilitazione dei vincoli non consente di utilizzare il troncamento, i vincoli dovrebbero essere eliminati e quindi ricreati


34
La disabilitazione dei vincoli NON consentirà il troncamento delle tabelle a cui fa riferimento un vincolo FOREIGN KEY. Il vincolo FK deve essere eliminato. Per favore, rispondi se sbaglio, ma non ho trovato alcun modo per evitare di lasciarli cadere.
Robert Claypool,

1
In questa istruzione EXEC sp_MSForEachTable non deve essere presente solo una parola chiave "Tabella" per errori di battitura "DELETE FROM TABLE?" La versione corretta dovrebbe essere: EXEC sp_MSForEachTable "DELETE FROM?"
Raghav,

4
Se stai usando SSMS 2008 o più recente, probabilmente vorrai aggiungere SET ROWCOUNT 0all'inizio dello script poiché l'impostazione predefinita è limitare le azioni a 500 righe! Riceverai errori frustranti come ho fatto io perché non tutti i dati saranno stati effettivamente eliminati.
Sean Hanley,

1
Questo ha funzionato alla grande. Nel mio caso ho anche dovuto aggiungere EXEC sp_msforeachtable "ALTER TABLE? Disabilita TRIGGER all" e EXEC sp_msforeachtable "ALTER TABLE? Abilita TRIGGER all" Prima e dopo l'istruzione delete.
RobC

2
La mia risposta preferita Ma perché (tutti, anche i commentatori) racchiudi stringhe SQL letterali tra virgolette?
bitooleano il

57

Ecco il re papà degli script di pulizia del database. Cancellerà tutte le tabelle e le ridimensionerà correttamente:

SET QUOTED_IDENTIFIER ON;
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? NOCHECK CONSTRAINT ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? DISABLE TRIGGER ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? CHECK CONSTRAINT ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? ENABLE TRIGGER ALL' 
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON';

IF NOT EXISTS (
    SELECT
        *
    FROM
        SYS.IDENTITY_COLUMNS
        JOIN SYS.TABLES ON SYS.IDENTITY_COLUMNS.Object_ID = SYS.TABLES.Object_ID
    WHERE
        SYS.TABLES.Object_ID = OBJECT_ID('?') AND SYS.IDENTITY_COLUMNS.Last_Value IS NULL
)
AND OBJECTPROPERTY( OBJECT_ID('?'), 'TableHasIdentity' ) = 1

    DBCC CHECKIDENT ('?', RESEED, 0) WITH NO_INFOMSGS;

Divertiti, ma fai attenzione!


2
Sfortunatamente il comando sopra fallisce se hai calcolato le colonne, poiché apparentemente sp_MSforeachtable ha SET QUOTED_IDENTITY OFFnel suo corpo ( link ). AGGIORNAMENTO: la correzione consiste nell'aggiungere "SET QUOTED_IDENTIFIERS su;" all'inizio di ogni affermazione che genera questo errore (come menzionato qui )
March

1
sembra che questo non abbia ridimensionato le mie identità
totooooo il

48

Il modo più semplice per farlo è farlo

  1. aprire SQL Management Studio
  2. vai al tuo database
  3. Fare clic con il tasto destro del mouse e selezionare Attività-> Genera script (foto 1)
  4. Nella schermata "scegli oggetti", seleziona l'opzione "seleziona oggetti specifici" e seleziona "tabelle" (figura 2)
  5. nella schermata successiva, selezionare "avanzato" e quindi modificare l'opzione "Script DROP and CREATE" su "Script DROP and CREATE" (foto 3)
  6. Scegliere di salvare lo script in una nuova finestra dell'editor o in un file ed eseguirlo come necessario.

questo ti darà uno script che rilascia e ricrea tutti i tuoi tavoli senza la necessità di preoccuparti del debug o se hai incluso tutto. Sebbene ciò funzioni più di un semplice troncato, i risultati sono gli stessi. Basta tenere presente che le chiavi primarie a incremento automatico inizieranno da 0, a differenza delle tabelle troncate che ricorderanno l'ultimo valore assegnato. Puoi anche eseguirlo dal codice se non hai accesso a Management Studio nei tuoi ambienti PreProd o Production.

1.

inserisci qui la descrizione dell'immagine

2.

inserisci qui la descrizione dell'immagine

3.

inserisci qui la descrizione dell'immagine


1
Attenzione se lo si utilizza per un database con uno schema molto complesso. L'ho provato su una copia di sviluppo del nostro DB di produzione e ha rovinato lo schema, richiedendo una ridistribuzione totale.
Techrocket9,

1
Devi scrivere tutte le cose che vuoi preservare
Capitano Kenpachi il

13

Il troncamento di tutte le tabelle funzionerà solo se non ci sono relazioni di chiave esterna tra le tabelle, poiché SQL Server non consente di troncare una tabella con una chiave esterna.

Un'alternativa a questa è quella di determinare le tabelle con chiavi esterne ed eliminare da queste prima, è quindi possibile troncare le tabelle senza chiavi esterne in seguito.

Vedere http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341 e http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 per ulteriori dettagli.


1
Buon punto. Non ci ho pensato. Potrei essere in grado di disabilitare prima tutti i vincoli e poi riattivarli una volta rimossi i dati.
Ray,

7

Un'opzione alternativa che mi piace usare con MSSQL Server Deveploper o Enterprise è quella di creare un'istantanea del database immediatamente dopo aver creato lo schema vuoto. A quel punto puoi semplicemente continuare a ripristinare il database nell'istantanea.


Sfortunatamente perdi tutti gli indici FULLTEXT ogni volta
Chris KL,

6

Non farlo! Davvero, non è una buona idea.

Se sai quali tabelle vuoi troncare, crea una procedura memorizzata che le tronca. È possibile correggere l'ordine per evitare problemi di chiave esterna.

Se vuoi davvero troncarli tutti (in modo da poterli caricare, ad esempio, BCP) saresti altrettanto veloce a eliminare il database e crearne uno nuovo da zero, con il vantaggio aggiuntivo di sapere esattamente dove ti trovi.


Bel approccio alternativo qui.
Sam,

3
il problema con il tuo approccio è che l'eliminazione delle tabelle e del database comporterebbe la perdita di tutte le autorizzazioni concesse a diversi accessi e schemi. Ricreare sarà doloroso per database di grandi dimensioni con molte tabelle.
Punit Vora,

4

Se si desidera conservare i dati in una particolare tabella (ad esempio una tabella di ricerca statica) durante l'eliminazione / troncamento dei dati in altre tabelle all'interno dello stesso db, è necessario un ciclo con le eccezioni al suo interno. Questo è quello che stavo cercando quando mi sono imbattuto in questa domanda.

sp_MSForEachTable mi sembra difettoso (ovvero comportamento incoerente con le istruzioni IF), probabilmente per questo non è documentato da MS.

declare @LastObjectID int = 0
declare @TableName nvarchar(100) = ''
set @LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > @LastObjectID order by [object_id])
while(@LastObjectID is not null)
begin
    set @TableName = (select top 1 [name] from sys.tables where [object_id] = @LastObjectID)

    if(@TableName not in ('Profiles', 'ClientDetails', 'Addresses', 'AgentDetails', 'ChainCodes', 'VendorDetails'))
    begin
        exec('truncate table [' + @TableName + ']')
    end 

    set @LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > @LastObjectID order by [object_id])
end

4

La parte più difficile del troncamento di tutte le tabelle è la rimozione e la ripubblicazione dei vincoli di chiave esterna.

La query seguente crea le istruzioni drop & create per ciascun vincolo relativo al nome di ciascuna tabella in @myTempTable. Se desideri generarli per tutte le tabelle, puoi semplicemente utilizzare lo schema informativo per raccogliere questi nomi di tabella.

DECLARE @myTempTable TABLE (tableName varchar(200))
INSERT INTO @myTempTable(tableName) VALUES
('TABLE_ONE'),
('TABLE_TWO'),
('TABLE_THREE')


-- DROP FK Contraints
SELECT 'alter table '+quotename(schema_name(ob.schema_id))+
  '.'+quotename(object_name(ob.object_id))+ ' drop constraint ' + quotename(fk.name) 
  FROM sys.objects ob INNER JOIN sys.foreign_keys fk ON fk.parent_object_id = ob.object_id
  WHERE fk.referenced_object_id IN 
      (
         SELECT so.object_id 
         FROM sys.objects so JOIN sys.schemas sc
         ON so.schema_id = sc.schema_id
         WHERE so.name IN (SELECT * FROM @myTempTable)  AND sc.name=N'dbo'  AND type in (N'U'))


 -- CREATE FK Contraints
 SELECT 'ALTER TABLE [PIMSUser].[dbo].[' +cast(c.name as varchar(255)) + '] WITH NOCHECK ADD CONSTRAINT ['+ cast(f.name as varchar(255)) +'] FOREIGN KEY (['+ cast(fc.name as varchar(255)) +'])
      REFERENCES [PIMSUser].[dbo].['+ cast(p.name as varchar(255)) +'] (['+cast(rc.name as varchar(255))+'])'
FROM  sysobjects f
      INNER JOIN sys.sysobjects c ON f.parent_obj = c.id
      INNER JOIN sys.sysreferences r ON f.id = r.constid
      INNER JOIN sys.sysobjects p ON r.rkeyid = p.id
      INNER JOIN sys.syscolumns rc ON r.rkeyid = rc.id and r.rkey1 = rc.colid
      INNER JOIN sys.syscolumns fc ON r.fkeyid = fc.id and r.fkey1 = fc.colid
WHERE 
      f.type = 'F'
      AND
      cast(p.name as varchar(255)) IN (SELECT * FROM @myTempTable)

Poi copio solo le istruzioni per l'esecuzione, ma con un po 'di sforzo dev puoi usare un cursore per eseguirle in modo dinamico.


3

È molto più facile (e forse anche più veloce) eseguire lo script del database, quindi rilasciarlo e crearlo dallo script.


3

Crea un database "modello" vuoto, esegui un backup completo. Quando è necessario aggiornare, è sufficiente ripristinare utilizzando WITH REPLACE. Veloce, semplice, antiproiettile. E se un paio di tabelle qui o là hanno bisogno di alcuni dati di base (ad es. Informazioni di configurazione o solo informazioni di base che fanno funzionare la tua app), anche questo gestisce.


2

Questo è un modo per farlo ... ce ne sono probabilmente altri 10 che sono migliori / più efficienti, ma sembra che questo sia fatto molto raramente, quindi ecco qui ...

ottenere un elenco di tablesda sysobjects, quindi scorrere su quelli con un cursore, chiamando sp_execsql('truncate table ' + @table_name)per ciascuno iteration.


aggiunto post con sql che fa proprio questo :) dato che questo era quello che stavo anche cercando.
Chris Smith,

1

Esegui una volta la sezione commentata, popola la tabella _TruncateList con le tabelle che desideri troncare, quindi esegui il resto dello script. La tabella _ScriptLog dovrà essere ripulita nel tempo se lo fai molto.

È possibile modificarlo se si desidera eseguire tutte le tabelle, basta inserire il nome SELECT INTO #TruncateList FROM sys.tables. Tuttavia, di solito non vuoi farli tutti.

Inoltre, ciò influirà su tutte le chiavi esterne nel database e puoi modificarlo anche se è troppo brusco per la tua applicazione. Non è per i miei scopi.

/*
CREATE TABLE _ScriptLog 
(
    ID Int NOT NULL Identity(1,1)
    , DateAdded DateTime2 NOT NULL DEFAULT GetDate()
    , Script NVarChar(4000) NOT NULL
)

CREATE UNIQUE CLUSTERED INDEX IX_ScriptLog_DateAdded_ID_U_C ON _ScriptLog
(
    DateAdded
    , ID
)

CREATE TABLE _TruncateList
(
    TableName SysName PRIMARY KEY
)
*/
IF OBJECT_ID('TempDB..#DropFK') IS NOT NULL BEGIN
    DROP TABLE #DropFK
END

IF OBJECT_ID('TempDB..#TruncateList') IS NOT NULL BEGIN
    DROP TABLE #TruncateList
END

IF OBJECT_ID('TempDB..#CreateFK') IS NOT NULL BEGIN
    DROP TABLE #CreateFK
END

SELECT Scripts = 'ALTER TABLE ' + '[' + OBJECT_NAME(f.parent_object_id)+ ']'+
' DROP  CONSTRAINT ' + '[' + f.name  + ']'
INTO #DropFK
FROM .sys.foreign_keys AS f
INNER JOIN .sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id

SELECT TableName
INTO #TruncateList
FROM _TruncateList

SELECT Scripts = 'ALTER TABLE ' + const.parent_obj + '
    ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
            ' + const.parent_col_csv + '
            ) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ')
'
INTO #CreateFK
FROM (
    SELECT QUOTENAME(fk.NAME) AS [const_name]
        ,QUOTENAME(schParent.NAME) + '.' + QUOTENAME(OBJECT_name(fkc.parent_object_id)) AS [parent_obj]
        ,STUFF((
                SELECT ',' + QUOTENAME(COL_NAME(fcP.parent_object_id, fcp.parent_column_id))
                FROM sys.foreign_key_columns AS fcP
                WHERE fcp.constraint_object_id = fk.object_id
                FOR XML path('')
                ), 1, 1, '') AS [parent_col_csv]
        ,QUOTENAME(schRef.NAME) + '.' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)) AS [ref_obj]
        ,STUFF((
                SELECT ',' + QUOTENAME(COL_NAME(fcR.referenced_object_id, fcR.referenced_column_id))
                FROM sys.foreign_key_columns AS fcR
                WHERE fcR.constraint_object_id = fk.object_id
                FOR XML path('')
                ), 1, 1, '') AS [ref_col_csv]
    FROM sys.foreign_key_columns AS fkc
    INNER JOIN sys.foreign_keys AS fk ON fk.object_id = fkc.constraint_object_id
    INNER JOIN sys.objects AS oParent ON oParent.object_id = fkc.parent_object_id
    INNER JOIN sys.schemas AS schParent ON schParent.schema_id = oParent.schema_id
    INNER JOIN sys.objects AS oRef ON oRef.object_id = fkc.referenced_object_id
    INNER JOIN sys.schemas AS schRef ON schRef.schema_id = oRef.schema_id
    GROUP BY fkc.parent_object_id
        ,fkc.referenced_object_id
        ,fk.NAME
        ,fk.object_id
        ,schParent.NAME
        ,schRef.NAME
    ) AS const
ORDER BY const.const_name

INSERT INTO _ScriptLog (Script)
SELECT Scripts
FROM #CreateFK

DECLARE @Cmd NVarChar(4000)
    , @TableName SysName

WHILE 0 < (SELECT Count(1) FROM #DropFK) BEGIN
    SELECT TOP 1 @Cmd = Scripts 
    FROM #DropFK

    EXEC (@Cmd)

    DELETE #DropFK WHERE Scripts = @Cmd
END

WHILE 0 < (SELECT Count(1) FROM #TruncateList) BEGIN
    SELECT TOP 1 @Cmd = N'TRUNCATE TABLE ' +  TableName
        , @TableName = TableName
    FROM #TruncateList

    EXEC (@Cmd)

    DELETE #TruncateList WHERE TableName = @TableName
END

WHILE 0 < (SELECT Count(1) FROM #CreateFK) BEGIN
    SELECT TOP 1 @Cmd = Scripts 
    FROM #CreateFK

    EXEC (@Cmd)

    DELETE #CreateFK WHERE Scripts = @Cmd
END

0

Non vedo perché cancellare i dati sarebbe meglio di uno script per eliminare e ricreare ogni tabella.

Quello o mantenere un backup del tuo DB vuoto e ripristinarlo su quello vecchio


2
Il motivo è il sovraccarico di eliminare e ricreare i file su disco del database, i registri, ecc. È enormemente lento. Pensa di cancellare il database 1.000 volte durante una discreta prova di unità.
Chris KL,

0

Prima di troncare le tabelle è necessario rimuovere tutte le chiavi esterne. Utilizzare questo script per generare script finali per eliminare e ricreare tutte le chiavi esterne nel database. Si prega di impostare la variabile @action su 'CREATE' o 'DROP'.


0

seleziona 'elimina da' + TABLE_NAME da INFORMATION_SCHEMA.TABLES dove TABLE_TYPE = 'BASE TABLE'

dove arriva il risultato.

Copia e incolla nella finestra della query ed esegui il comando


0

È un po 'tardi ma potrebbe aiutare qualcuno. A volte ho creato una procedura che fa quanto segue usando T-SQL:

  1. Memorizzare tutti i vincoli in una tabella temporanea
  2. Elimina tutti i vincoli
  3. Troncare tutte le tabelle ad eccezione di alcune tabelle, che non richiedono il troncamento
  4. Ricrea tutti i vincoli.

L'ho elencato sul mio blog qui

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.