web-dev-qa-db-fra.com

Comment tronquer toutes les tables d'une base de données à l'aide de TSQL?

J'ai un environnement de test pour une base de données que je souhaite recharger avec de nouvelles données au début d'un cycle de test. Je ne suis pas intéressé par la reconstruction de la base de données complète - il suffit de "redéfinir" les données. 

Quel est le meilleur moyen de supprimer toutes les données de toutes les tables en utilisant TSQL? Existe-t-il des procédures, vues, etc. stockées dans le système pouvant être utilisées? Je ne veux pas créer et maintenir manuellement des instructions de table tronquées pour chaque table. Je préférerais que ce soit dynamique.

187
Ray Vega

Pour SQL 2005, 

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

Quelques autres liens pour 2000 et 2005/2008 ..

173
Gulzar Nazim

Lors de la suppression de données de tables avec des relations de clé étrangère (ce qui est fondamentalement le cas de toute base de données correctement conçue), nous pouvons désactiver toutes les contraintes, supprimer toutes les données, puis réactiver les contraintes.

-- 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"

Plus d'informations sur la désactivation des contraintes et des déclencheurs ici

si certaines des tables ont des colonnes d'identité, nous pouvons vouloir les réensemencer

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

Notez que le comportement de RESEED diffère entre le tout nouveau tableau et celui dans lequel des données avaient déjà été insérées depuis BOL :

DBCC CHECKIDENT ('nom_table', RESEED, newReseedValue)

La valeur d'identité actuelle est définie sur le nouveauResedValue. Si aucune ligne n'a été inséré dans la table depuis le a été créé, la première ligne insérée après avoir exécuté DBCC CHECKIDENT sera utilisez newReseedValue comme identité . Sinon, la prochaine ligne insérée sera utilisez newReseedValue + 1. Si la valeur de newReseedValue est inférieure à la valeur maximale dans la colonne identité, le message d'erreur 2627 sera généré sur les références ultérieures à la table.

Merci à Robert d’avoir souligné le fait que la désactivation des contraintes ne permet pas d’utiliser troncature, il faudrait alors les supprimer, puis les recréer.

392
kristof

Voici le roi papa des scripts de nettoyage de base de données. Cela effacera toutes les tables et les réensemencera correctement:

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'

Profitez-en, mais soyez prudent!

48
Chris KL

Le moyen le plus simple de le faire est de 

  1. ouvrir SQL Management Studio
  2. accédez à votre base de données
  3. Cliquez avec le bouton droit de la souris et sélectionnez Tâches-> Générer des scripts (photo 1).
  4. Dans l'écran "Choisir des objets", sélectionnez l'option "Sélectionner des objets spécifiques" et cochez la case "Tableaux" (photo 2).
  5. sur l'écran suivant, sélectionnez "avancé" puis changez l'option "Script DROP and CREATE" en "Script DROP and CREATE" (photo 3)
  6. Choisissez d'enregistrer le script dans une nouvelle fenêtre d'édition ou dans un fichier et exécutez-le si nécessaire.

cela vous donnera un script qui supprime et recrée toutes vos tables sans avoir à vous soucier du débogage ou de l'inclusion de tout. Bien que cela ne se limite pas à un tronçon, les résultats sont les mêmes. Gardez simplement à l'esprit que vos clés primaires auto-incrémentées commenceront à 0, par opposition aux tables tronquées qui se souviendront de la dernière valeur affectée. Vous pouvez également exécuter cette opération à partir de code si vous n'avez pas accès à Management Studio sur vos environnements de préproduction ou de production.

1.

enter image description here

2.

enter image description here

3.

enter image description here

41
Captain Kenpachi

La troncature de toutes les tables ne fonctionnera que si vous n'avez aucune relation de clé étrangère entre elles, car SQL Server ne vous permettra pas de tronquer une table avec une clé étrangère.

Une autre solution consiste à déterminer les tables avec des clés étrangères et à les supprimer en premier. Vous pouvez ensuite tronquer les tables sans clés étrangères par la suite.

Voir http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341 et http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 pour plus d'informations. détails.

12
marcj

Une option alternative que j'aime utiliser avec MSSQL Server Deveploper ou Enterprise consiste à créer un instantané de la base de données immédiatement après la création du schéma vide. À ce stade, vous pouvez simplement continuer à restaurer la base de données vers l'instantané.

7
Chris Chilvers

Ne fais pas ça! Vraiment pas une bonne idée.

Si vous savez quelles tables vous souhaitez tronquer, créez une procédure stockée qui les tronque. Vous pouvez corriger la commande pour éviter les problèmes de clé étrangère.

Si vous voulez vraiment les tronquer tous (afin que vous puissiez les charger par BCP par exemple), vous serez tout aussi rapide pour supprimer la base de données et en créer une nouvelle à partir de zéro, ce qui aurait l'avantage supplémentaire de savoir exactement où vous vous trouvez.

6
Ben Liddicott

Si vous souhaitez conserver des données dans une table particulière (c'est-à-dire une table de consultation statique) tout en supprimant/tronquant des données dans d'autres tables de la même base de données, vous avez besoin d'une boucle avec les exceptions qu'elle contient. C'est ce que je cherchais lorsque je suis tombé sur cette question. 

sp_MSForEachTable me semble bogué (comportement incohérent avec les instructions IF), ce qui explique probablement pourquoi il n'est pas documenté par 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
Chris Smith

La partie la plus difficile de la troncature de toutes les tables est de supprimer et de rajouter les contraintes de clé étrangère.

La requête suivante crée les instructions drop & create pour chaque contrainte relative à chaque nom de table dans @myTempTable. Si vous souhaitez les générer pour toutes les tables, vous pouvez simplement utiliser le schéma d’information pour rassembler ces noms de table.

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)

Je copie ensuite simplement les instructions à exécuter - mais avec un peu d'effort de développement, vous pouvez utiliser un curseur pour les exécuter de manière dynamique.

3
Scott Allen

Créez une base de données "modèle" vide, effectuez une sauvegarde complète. Lorsque vous avez besoin d'actualiser, il vous suffit de restaurer en utilisant WITH REPLACE. Rapide, simple, à l'épreuve des balles. Et si quelques tables ici ou là nécessitent des données de base (par exemple, des informations de configuration ou simplement des informations de base permettant à votre application de s'exécuter), elle les gère également.

3
onupdatecascade

Il est beaucoup plus facile (et peut-être même plus rapide) de créer un script pour votre base de données, puis supprimez-la et créez-la à partir du script.

2
A-K

C'est une une façon de le faire ... il y a probablement 10 autres qui sont meilleures/plus efficaces, mais il semblerait que cela se fasse très rarement, alors allez-y ...

obtenez une liste de tables à partir de sysobjects, puis parcourez celles avec un curseur en appelant sp_execsql('truncate table ' + @table_name) pour chaque iteration.

2
Ben Scheirman

J'aurais la chance d'ajouter une autre réponse ... et pour aggraver encore les choses, c'est presque une réponse en lien uniquement. J'ai posté une réponse ici à une question différente mais liée SO, qui crée une procédure stockée semblable à plusieurs réponses à cette question ... mais je pense qu'elle dépasse un certain nombre de problèmes étranges (plusieurs schémas, noms de contraintes étranges, annulation et quelques autres). Voyez ce que vous en pensez. Cela crée une procédure appelée TruncateTables, et si vous voulez détruire toute la base de données, appelez-la ainsi:

declare @t dbo.NamesType  --> this simple table type is also defined in the other answer
insert @t select schema_name(t.schema_id) + N'.' + t.name from sys.tables t
execute dbo.TruncateTables @t ,0

Peut-être que ça vous fera plaisir. J'espere!

0
Clay

Exécutez la section commentée une fois, remplissez la table _TruncateList avec les tables à tronquer, puis exécutez le reste du script. La table _ScriptLog devra être nettoyée au fil du temps si vous faites cela souvent.

Vous pouvez modifier cela si vous voulez faire toutes les tables, il suffit de mettre SELECT nom INTO #TruncateList FROM sys.tables. Cependant, vous ne voulez généralement pas tous les faire.

En outre, cela affectera toutes les clés étrangères de la base de données. Vous pouvez également le modifier s'il est trop brutal pour votre application. Ce n'est pas pour mes besoins.

/*
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
Steve Hood

Avant de tronquer les tables, vous devez supprimer toutes les clés étrangères. Utilisez ce script pour générer les scripts finaux permettant de supprimer et de recréer toutes les clés étrangères de la base de données. Définissez la variable @action sur 'CREATE' ou 'DROP'.

0
Edward Weinert

sélectionnez 'delete from' + TABLE_NAME from INFORMATION_SCHEMA.TABLES où TABLE_TYPE = 'BASE TABLE'

où le résultat vient.

Copier et coller dans la fenêtre de requête et exécuter la commande

0
Somendra Tiwari

C'est un peu tard, mais cela pourrait aider quelqu'un ..__ J'ai créé parfois une procédure de retour qui effectue les opérations suivantes à l'aide de T-SQL:

  1. Stocker toutes les contraintes dans une table temporaire
  2. Supprimer toutes les contraintes
  3. Tronquer toutes les tables à l'exception de certaines tables, qui ne nécessitent pas de troncature
  4. Recréer toutes les contraintes.

Je l'ai répertorié sur mon blog ici

0
Mohit

Je ne vois pas pourquoi l'effacement des données serait préférable à un script pour supprimer et recréer chaque table.

Cela ou garder une sauvegarde de votre base de données vide et le restaurer sur l'ancien

0
Brian Spencer