¿Cómo truncar todas las tablas en una base de datos usando TSQL?

204

Tengo un entorno de prueba para una base de datos que quiero volver a cargar con datos nuevos al comienzo de un ciclo de prueba. No estoy interesado en reconstruir toda la base de datos, simplemente "restablecer" los datos.

¿Cuál es la mejor manera de eliminar todos los datos de todas las tablas con TSQL? ¿Existen procedimientos almacenados del sistema, vistas, etc. que puedan usarse? No quiero crear y mantener manualmente declaraciones de tabla truncadas para cada tabla; preferiría que fuera dinámico.

Rayo
fuente

Respuestas:

188

Para SQL 2005,

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

Un par de enlaces más para 2000 y 2005/2008 .

Gulzar Nazim
fuente
62
No puede truncar las tablas que tienen claves foráneas, por lo que esto solo funcionará si no hay restricciones de claves foráneas entre las tablas (o si se han deshabilitado).
marcj
1
Estuve de acuerdo ... pensé que ya que específicamente pedía truncar tablas, ya resolvió el problema con claves foráneas ...
Gulzar Nazim
@ gulzar, más o menos, publiqué una pregunta por separado sobre cómo manejar los FK, pero su respuesta se basa en sus propios méritos.
Ray
11
@ Sam: ¡No, no lo hará! Los datos en las tablas son irrelevantes. Mientras haya una restricción de clave externa que haga referencia a la tabla (incluso una deshabilitada), no puede truncarla.
TToni
3
'EXEC sp_MSForEachTable' DROP TABLE? ' Funciona muy bien también :) (deleitando todas las tablas de la base de datos)
kuncevic.dev
419

Cuando se trata de eliminar datos de tablas que tienen relaciones de clave externa, que es básicamente el caso con cualquier base de datos diseñada adecuadamente, podemos desactivar todas las restricciones, eliminar todos los datos y luego volver a habilitar las restricciones

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

Más sobre deshabilitar restricciones y disparadores aquí

Si algunas de las tablas tienen columnas de identidad, podemos resetearlas

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

Tenga en cuenta que el comportamiento de RESEED difiere entre una tabla nueva y una que había tenido algunos datos insertados previamente de BOL :

DBCC CHECKIDENT ('nombre_tabla', RESEED, newReseedValue)

El valor de identidad actual se establece en newReseedValue. Si no se han insertado filas en la tabla desde que se creó, la primera fila insertada después de ejecutar DBCC CHECKIDENT utilizará newReseedValue como identidad. De lo contrario, la siguiente fila insertada utilizará newReseedValue + 1. Si el valor de newReseedValue es menor que el valor máximo en la columna de identidad, se generará el mensaje de error 2627 en las referencias posteriores a la tabla.

Gracias a Robert por señalar el hecho de que deshabilitar las restricciones no permite usar truncar, las restricciones tendrían que eliminarse y luego recrearse

kristof
fuente
34
Deshabilitar las restricciones NO permitirá el truncamiento de tablas a las que hace referencia una restricción FOREIGN KEY. La restricción FK tiene que ser eliminada. Responda si estoy equivocado sobre esto, pero no he encontrado la manera de evitar que se caigan.
Robert Claypool
1
Solo una palabra clave tipográfica "Tabla" no debería estar allí en esta declaración EXEC sp_MSForEachTable "¿ELIMINAR DE LA TABLA?" La versión correcta debe ser: EXEC sp_MSForEachTable "DELETE FROM?"
Raghav
44
Si está utilizando SSMS 2008 o más nuevos, ¡probablemente desee agregarlos SET ROWCOUNT 0al comienzo de su script, ya que el valor predeterminado es limitar las acciones a 500 filas! Obtendrá errores frustrantes como lo hice yo porque no todos los datos se habrán eliminado.
Sean Hanley
1
Esto funcionó muy bien. En mi caso, también tuve que agregar EXEC sp_msforeachtable "ALTER TABLE? Disable TRIGGER all" y EXEC sp_msforeachtable "ALTER TABLE? Enable TRIGGER all" Antes y después de la declaración de eliminación.
RobC
2
Mi respuesta favorita Pero, ¿por qué (todos, incluso los comentaristas) incluyen cadenas SQL literales entre comillas dobles?
bitooleano
57

Aquí está el rey papá de los scripts de limpieza de bases de datos. Borrará todas las tablas y las reiniciará correctamente:

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;

¡Disfruta, pero ten cuidado!

Chris KL
fuente
2
Desafortunadamente, el comando anterior falla si tiene columnas calculadas, ya que sp_MSforeachtable aparentemente tiene SET QUOTED_IDENTITY OFFen su cuerpo ( enlace ). ACTUALIZACIÓN: La solución es agregar "SET QUOTED_IDENTIFIERS on"; al comienzo de cada declaración que genera este error (como se menciona aquí )
Marchy
1
parece que esto no volvió a sembrar mis identidades
totooooo
48

La forma más sencilla de hacer esto es

  1. abrir SQL Management Studio
  2. navegar a su base de datos
  3. Haga clic derecho y seleccione Tareas-> Generar guiones (imagen 1)
  4. En la pantalla "elegir objetos", seleccione la opción "seleccionar objetos específicos" y marque "tablas" (imagen 2)
  5. en la siguiente pantalla, seleccione "avanzado" y luego cambie la opción "DROP Script y CREATE" a "DROP Script y CREATE" (foto 3)
  6. Elija guardar la secuencia de comandos en una nueva ventana del editor o un archivo y ejecutar según sea necesario.

esto le dará un script que descarta y recrea todas sus tablas sin la necesidad de preocuparse por la depuración o si ha incluido todo. Si bien esto realiza más que solo un truncamiento, los resultados son los mismos. Solo tenga en cuenta que sus claves primarias de incremento automático comenzarán en 0, a diferencia de las tablas truncadas que recordarán el último valor asignado. También puede ejecutar esto desde el código si no tiene acceso a Management studio en sus entornos PreProd o Production.

1)

ingrese la descripción de la imagen aquí

2)

ingrese la descripción de la imagen aquí

3)

ingrese la descripción de la imagen aquí

Capitán Kenpachi
fuente
1
Tenga cuidado si usa esto para una base de datos con un esquema muy complejo. Lo probé en una copia de desarrollo de nuestra base de datos de producción y destruyó el esquema, lo que requirió una nueva implementación total.
Techrocket9
1
Tienes que escribir todas las cosas que quieres preservar
Capitán Kenpachi el
13

Truncar todas las tablas solo funcionará si no tiene ninguna relación de clave externa entre sus tablas, ya que SQL Server no le permitirá truncar una tabla con una clave externa.

Una alternativa a esto es determinar las tablas con claves foráneas y eliminarlas primero, luego puede truncar las tablas sin claves foráneas después.

Consulte http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341 y http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 para obtener más detalles.

marcj
fuente
1
Buen punto. No pensé en eso. Es posible que pueda deshabilitar todas las restricciones primero y luego volver a habilitarlas una vez que se hayan eliminado los datos.
Ray
7

Una opción alternativa que me gusta usar con MSSQL Server Deveploper o Enterprise es crear una instantánea de la base de datos inmediatamente después de crear el esquema vacío. En ese momento, puede seguir restaurando la base de datos a la instantánea.

Chris Chilvers
fuente
Desafortunadamente, pierde todos sus índices FULLTEXT cada vez
Chris KL
6

¡No hagas esto! Realmente, no es una buena idea.

Si sabe qué tablas desea truncar, cree un procedimiento almacenado que las trunca. Puede arreglar el pedido para evitar problemas de claves externas.

Si realmente desea truncarlos a todos (para poder cargarlos BCP, por ejemplo), sería tan rápido como soltar la base de datos y crear una nueva desde cero, lo que tendría el beneficio adicional de saber exactamente dónde se encuentra.

Ben Liddicott
fuente
Buen enfoque alternativo aquí.
Sam
3
El problema con su enfoque es que si se eliminan las tablas y la base de datos, se perderían todos los permisos otorgados a diferentes inicios de sesión y esquemas. Volver a crear eso será doloroso para grandes bases de datos con muchas tablas.
Punit Vora
4

Si desea mantener los datos en una tabla en particular (es decir, una tabla de búsqueda estática) mientras elimina / trunca datos en otras tablas dentro de la misma base de datos, entonces necesita un bucle con las excepciones. Esto es lo que estaba buscando cuando me topé con esta pregunta.

sp_MSForEachTable me parece defectuoso (es decir, comportamiento inconsistente con las declaraciones IF), lo que probablemente sea la razón por la cual MS no lo documenta.

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
Chris Smith
fuente
4

La parte más difícil de truncar todas las tablas es eliminar y volver a agregar las restricciones de clave externa.

La siguiente consulta crea las instrucciones drop & create para cada restricción relacionada con cada nombre de tabla en @myTempTable. Si desea generarlos para todas las tablas, puede simplemente usar el esquema de información para recopilar estos nombres de tabla.

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)

Luego simplemente copie las declaraciones para ejecutarlas, pero con un poco de esfuerzo de desarrollo podría usar un cursor para ejecutarlas dinámicamente.

Scott Allen
fuente
3

Es mucho más fácil (y posiblemente incluso más rápido) crear una secuencia de comandos de su base de datos, luego simplemente soltarla y crearla desde la secuencia de comandos.

Alaska
fuente
3

Haga una base de datos de "plantilla" vacía, realice una copia de seguridad completa. Cuando necesite actualizar, simplemente restaure usando WITH REPLACE. Rápido, simple, a prueba de balas. Y si un par de tablas aquí o allá necesitan algunos datos de base (por ejemplo, información de configuración, o simplemente información básica que hace que su aplicación se ejecute), también lo maneja.

onupdatecascade
fuente
2

Este es uno forma de hacerlo ... es probable que haya otros 10 que sean mejores / más eficientes, pero parece que esto se hace con poca frecuencia, así que aquí va ...

obtenga una lista de tablesfrom sysobjects, luego repita sobre aquellos con un cursor, llamando sp_execsql('truncate table ' + @table_name)a cada uno iteration.

Ben Scheirman
fuente
Publicación agregada con SQL que hace exactamente esto :) ya que esto era lo que estaba buscando también.
Chris Smith
1

Ejecute la sección comentada una vez, complete la tabla _TruncateList con las tablas que desea truncar y luego ejecute el resto del script. La tabla _ScriptLog deberá limpiarse con el tiempo si hace esto mucho.

Puede modificar esto si desea hacer todas las tablas, simplemente ingrese el nombre SELECCIONAR EN #TruncateList FROM sys.tables. Sin embargo, generalmente no quieres hacerlos todos.

Además, esto afectará a todas las claves foráneas en la base de datos, y puede modificar eso también si es demasiado contundente para su aplicación. No es para mis propósitos.

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

No veo por qué borrar datos sería mejor que un script para soltar y volver a crear cada tabla.

Eso o mantener una copia de seguridad de su base de datos vacía y restaurarla sobre la anterior

Brian Spencer
fuente
2
La razón es que la sobrecarga de soltar y recrear los archivos, registros, etc. en disco de la base de datos es enormemente lenta. Piense en limpiar la base de datos 1,000 veces durante una ejecución de prueba de unidad decente.
Chris KL
0

Antes de truncar las tablas, debe eliminar todas las claves foráneas. Use este script para generar los scripts finales para descartar y recrear todas las claves foráneas en la base de datos. Establezca la variable @action en 'CREATE' o 'DROP'.

Edward Weinert
fuente
0

seleccione 'eliminar de' + TABLE_NAME de INFORMATION_SCHEMA.TABLES donde TABLE_TYPE = 'BASE TABLE'

de donde viene el resultado.

Copie y pegue en la ventana de consulta y ejecute el comando

Somendra Tiwari
fuente
0

Es un poco tarde pero podría ayudar a alguien. A veces creé un procedimiento que hace lo siguiente usando T-SQL:

  1. Almacenar todas las restricciones en una tabla temporal
  2. Descarte todas las restricciones
  3. Truncar todas las tablas con excepción de algunas tablas, que no necesitan truncamiento
  4. Recrea todas las restricciones.

Lo he enumerado en mi blog aquí.

Mohit
fuente