2008-09-30 7 views
171

Tengo un entorno de prueba para una base de datos que deseo volver a cargar con nuevos datos al comienzo de un ciclo de prueba. No estoy interesado en reconstruir toda la base de datos, simplemente "restableciendo" los datos.¿Cómo se truncan todas las tablas en una base de datos utilizando TSQL?

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

Respuesta

157

Para SQL 2005,

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?' 

par de enlaces para 2000 y 2005/2008 ..

+47

No puede truncar tablas que tienen claves foráneas, por lo que esto solo funcionará si no hay restricciones de clave externa entre tablas (o si se han deshabilitado). – marcj

+0

de acuerdo ... pensé que ya que pidió específicamente truncar las tablas, ya resolvió el problema con las claves externas ... –

+0

@ gulzar- una especie de- publiqué una pregunta separada sobre cómo manejar las FK pero su respuesta se basa en sus propios méritos . –

2

Este es uno manera de hacerlo ... hay probablemente otras 10 que son mejores/más eficiente, pero parece que esto se hace con muy poca frecuencia, así que aquí va ...

obtener una lista de las tablas de sysobjects, luego recorra las que tienen un cursor, llamando a sp_execsql ('truncate table' + @table_name) para cada iteración.

+0

añadida la publicación con sql que hace justamente esto :) ya que esto era lo que estaba buscando también. –

12

Truncado de todas las tablas sólo funcionará si usted no tiene ninguna relación de clave externa entre las tablas, como SQL Server no le permitirá truncar una tabla con una clave externa.

Una alternativa a esto es determinar las tablas con claves externas y eliminarlas primero, luego puede truncar las tablas sin claves externas 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 información.

+0

Buen punto. No pensé en eso. yo podría ser capaz de desactivar todas las restricciones primero y luego volver a activarlos una vez que los datos se han eliminado. –

365

Cuando se trata de la eliminación de datos de las tablas que tienen relaciones de clave externa - que es básicamente el caso con cualquier base de datos correctamente diseñada - podemos desactivar todas las restricciones, borrar 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 acerca de las limitaciones de discapacidad y desencadena here

si algunas de las mesas tienen columnas de identidad podemos querer sembrar de nuevo a

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

Tenga en cuenta que el comportamiento de RESEED diferencia entre la marca nueva tabla, y uno que había tenido algunos datos insertados previamente de BOL:

DBCC CHECKIDENT ('nombre_tabla', RESEED, newReseedValue)

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

Gracias a Robert por señalar el hecho de que la desactivación limitaciones no permite utilizar truncado, las restricciones tendrían que ser entregados, y luego se vuelven a crear

+24

La desactivación de restricciones NO permitirá el truncamiento de las tablas a las que hace referencia una restricción FOREIGN KEY. La restricción FK tiene que ser eliminada. Por favor, responda si me equivoco al respecto, pero no he encontrado forma de evitar dejarlos caer. –

+0

Gracias Robert, tienes razón. Gracias por señalar esto. He actualizado mi respuesta. – kristof

+1

Solo una palabra clave de error "Tabla" no debería estar en esta declaración EXEC sp_MSForEachTable "¿ELIMINAR DE LA TABLA?" . La versión correcta debe ser: EXEC sp_MSForEachTable "DELETE FROM?" – Raghav

6

No haga esto! Realmente, no es una buena idea.

Si sabe qué tablas desea truncar, cree un procedimiento almacenado que las trunque. Puede solucionar el problema para evitar problemas de claves externas.

Si realmente quieres truncarlos a todos (para que puedas cargarlos BCP por ejemplo), serás igual de rápido para dejar la base de datos y crear uno nuevo desde cero, lo que tendría la ventaja adicional de que sabes exactamente Dónde estás.

+0

Buen enfoque alternativo aquí. – Sam

+3

el problema con su enfoque es que eliminar las tablas de la base de datos y se traduciría en la pérdida de todos los permisos que fueron entregados a diferentes nombres de usuario y esquemas. Recrear eso va a ser doloroso para grandes bases de datos con muchas tablas. – desigeek

0

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

Eso o mantener una copia de seguridad de su vacío DB y restaurarla más de un

+2

La razón es que la sobrecarga de dejar caer y volver a crear la base de datos en los archivos del disco, registros, etc. es enormemente lenta. Piense en limpiar la base de datos 1.000 veces durante una ejecución de prueba de la unidad decente. Desafortunadamente –

7

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

+0

se pierden todos los índices FULLTEXT cada vez –

2

Es mucho más fácil (y posiblemente incluso más rápido) crear una secuencia de comandos de su base de datos, luego solo suelte y créelo desde el script.

3

Haga una base de datos de "plantilla" vacía, haga 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 maneja eso.

38

Aquí está el rey papi de las secuencias de comandos para borrar la base de datos. Vaciará todas las tablas y las resembrará 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' 

Disfrútelo, pero tenga cuidado!

+2

Desafortunadamente el comando anterior falla si ha calculado columnas, ya que al parecer ha sp_MSforeachtable 'set QUOTED_IDENTITY OFF' en su cuerpo ([link] (http://spicyjoe.blogspot.ca/2012 /01/delete-contents-of-tables.html)). ACTUALIZACIÓN: la solución es agregar "SET QUOTED_IDENTIFIERS on"; al principio de cada declaración que plantea este error (como se mencionó [aquí] (http://markeboyle.wordpress.com/2012/07/04/beware-the-sp_msforeachtable-sets-quoted_identifier-off/)) – Marchy

+0

@Marchy , "SET QUOTED_IDENTIFIER on"; para ser correcto – Vado

0

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

-1

seleccione 'eliminar de' + TABLE_NAME de INFORMATION_SCHEMA.TABLES donde TABLE_TYPE = 'Base de mesa'

donde result venir.

Copiar y pegar en la ventana de consulta y ejecute el comando

3

Si desea conservar los datos en una tabla en particular (es decir, una tabla de consulta estática) mientras borra/truncar los datos de otras tablas dentro de la misma db, entonces necesita un bucle con las excepciones en él. Esto es lo que estaba buscando cuando tropecé con esta pregunta.

sp_MSForEachTable parece un error para mí (es decir, comportamiento incoherente con las declaraciones IF) que es probablemente la razón por la cual no está documentado por 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 
0

Ejecutar la sección comentada a cabo una vez, rellenar la tabla _TruncateList con las tablas que desea truncada, a continuación, ejecutar el resto de la secuencia de comandos. La tabla _ScriptLog tendrá que limpiarse con el tiempo si haces esto mucho.

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

Además, esto afectará a todas las claves externas en la base de datos, y usted 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 
34

La forma más sencilla de hacer esto es a

  1. abren SQL Management Studio
  2. vaya a su base de datos
  3. derecho del ratón y seleccione Tareas de> generar secuencias de comandos (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 n, seleccione "advanced" y luego cambie la opción "Script DROP and CREATE" a "Script DROP and CREATE" (foto 3)
  6. Elija guardar el script en una nueva ventana del editor o un archivo y ejecutar según sea necesario.

esto le dará un guión que cae y vuelve a crear todas las tablas sin la necesidad de preocuparse acerca de la depuración o si usted ha incluido todo. Mientras esto realiza más que solo un truncado, 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.

enter image description here

2.

enter image description here

3.

enter image description here

+2

esta es una manera perfecta, gracias !! – Winson

+0

Tenga cuidado si usa esto para una base de datos con un esquema muy complejo. Lo intenté en una copia de desarrollo de nuestro DB de producción y destruyó el esquema, requiriendo una redistribución total. – Techrocket9

+0

Tienes que escribir todas las cosas que quieras conservar –

2

La parte más difícil de truncar todas las tablas es la eliminación y reajustar las restricciones de clave externa.

La siguiente consulta crea las declaraciones drop & create para cada restricción relacionada con cada nombre de tabla en @myTempTable. Si desea generar estos para todas las tablas, puede usar el esquema de información para reunir 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) 

que luego simplemente copiar las sentencias que se ejecutarán - pero con un poco de esfuerzo dev Se puede usar un cursor para funcionar de forma dinámica.

Cuestiones relacionadas