¿No se puede truncar la tabla porque está siendo referenciada por una restricción FOREIGN KEY?

459

Con MSSQL2005, ¿puedo truncar una tabla con una restricción de clave externa si primero trunco ​​la tabla secundaria (la tabla con la clave primaria de la relación FK)?

Sé que puedo

  • Use una DELETEcláusula sin y luego RESEEDla identidad (o)
  • Elimina el FK, trunca la tabla y vuelve a crear el FK.

Pensé que mientras truncara la tabla secundaria antes que la matriz, estaría bien sin hacer ninguna de las opciones anteriores, pero obtengo este error:

No se puede truncar la tabla 'TableName' porque está siendo referenciada por una restricción FOREIGN KEY.

ctrlShiftBryan
fuente

Respuestas:

379

Correcto; no puede truncar una tabla que tiene una restricción FK.

Normalmente mi proceso para esto es:

  1. Suelta las restricciones
  2. Trunc la mesa
  3. Recrea las restricciones.

(Todo en una transacción, por supuesto).

Por supuesto, esto solo se aplica si el niño ya ha sido truncado. De lo contrario, voy por una ruta diferente, dependiendo completamente de cómo se vean mis datos. (Demasiadas variables para entrar aquí).

El póster original determinó POR QUÉ este es el caso; Vea esta respuesta para más detalles.

John Rudy
fuente
73
Un "DELETE FROM" no restablece las columnas de incremento automático. Un truncado hace. No son funcionalmente equivalentes.
robross0606
35
Truncar es a menudo exactamente lo que quieres hacer si estás eliminando grandes cantidades de datos. ¿Truncar un millón de filas? Mil millones? 1 ms ... entonces, @ M07, no digas "borrar del enfoque es más limpio", porque eso no es ni remotamente exacto.
ctb
1
Después de eliminar datos grandes, el usuario debe reducir las tablas y los archivos de registro también para recuperar el espacio en disco.
Muhammad Yousaf Sulahria
2
El botón Magic Shrink (o script) no se recomienda el 99% del tiempo.
Tom Stickel
1
¿Y cómo harías eso? Solicitudes de ejemplo?
jeromej
357
DELETE FROM TABLENAME
DBCC CHECKIDENT ('DATABASENAME.dbo.TABLENAME',RESEED, 0)

Tenga en cuenta que esto probablemente no sea lo que desearía si tiene más de millones de registros, ya que es muy lento.

s15199d
fuente
Esa fue una forma útil y más rápida que deshabilitar y habilitar la restricción.
sensei
Esto solo funcionará para la tabla con menos datos. De acuerdo con @Pure
Dhanuka777
1
Esto es genial para cuando haya terminado de probar un esquema
ohmusama
3
No sugeriría seguir esta ruta, ya que también podría obtener este error: la instrucción DELETE está en conflicto con la restricción REFERENCE
sksallaj
No funciono para mi. Aún obteniendo la declaración DELETE en conflicto con la restricción REFERENCE.
emirhosseini
192

Debido a que TRUNCATE TABLEes un comando DDL , no puede verificar si los registros en la tabla están siendo referenciados por un registro en la tabla secundaria.

Es por eso que DELETEfunciona y TRUNCATE TABLEno funciona: porque la base de datos puede asegurarse de que otro registro no haga referencia a ella.

ctrlShiftBryan
fuente
92

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

Como procedimiento almacenado

https://github.com/reduardo7/TableTruncate

Tenga en cuenta que esto probablemente no sea lo que desearía si tiene millones de registros, ya que es muy lento.

Eduardo Cuomo
fuente
3
usando reseed new value = 1 después de DELETE FROM comenzaría todo desde ID 2, en lugar de 1. From Technet ( technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx ) Si no se han colocado filas insertado en la tabla desde que se creó, o todas las filas se han eliminado mediante la instrucción TRUNCATE TABLE, la primera fila insertada después de ejecutar DBCC CHECKIDENT usa new_reseed_value como identidad. De lo contrario, la siguiente fila insertada usa new_reseed_value + el valor de incremento actual.
Zoran P.
@ZoranP. consulte la variante de Procedimiento almacenado: github.com/reduardo7/TableTruncate
Eduardo Cuomo
44
DBCC CHECKIDENT ([TableName], RESEED, 0) no 1
Tico Fortes
1
@TicoFortes Publicación actualizada. Consulte la variante de procedimiento almacenado
Eduardo Cuomo
1
Este no es un buen enfoque. Como comentaron las otras 700 versiones de esta misma respuesta a esta pregunta. A MENOS QUE su base de datos esté en modo de recuperación simple, para limitar el registro de transacciones.
pimbrouwers
68

La solución que @denver_citizen proporcionó anteriormente no funcionó para mí, pero me gustó su espíritu, así que modifiqué algunas cosas:

  • lo convirtió en un procedimiento almacenado
  • cambió la forma en que las claves externas se rellenan y se recrean
  • el script original trunca todas las tablas referenciadas, esto puede causar un error de violación de clave externa cuando la tabla referenciada tiene otras referencias de clave externa. Este script trunca solo la tabla especificada como parámetro. Depende del usuario llamar a este procedimiento almacenado varias veces en todas las tablas en el orden correcto

Para el beneficio del público, aquí está el script actualizado:

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
Peter Szanto
fuente
11
¡Esta respuesta merece más votos! De hecho, con gusto te compraría una cerveza si pudiera, Peter :)
nsimeonov
Esto fue de gran ayuda para mí hoy para borrar rápidamente algunas tablas grandes de sus datos para las pruebas. Gracias por el trabajo de calidad en esto.
Craig Selbert
44
Gracias por este fragmento de código. Pero cuidado, debe agregar una lógica adicional para verificar los FK deshabilitados. De lo contrario, habilitará las restricciones actualmente deshabilitadas.
Andre Figueiredo
2
Hice una versión con las sugerencias de @AndreFigueiredo. Lo estoy poniendo en Gitlab: gitlab.com/ranolfi/truncate-referenced-table . Siéntase libre de incorporar el código a su respuesta.
Marc.2377
1
Esto es genial, pero tenga en cuenta que no funcionará si sus tablas no están en el esquema predeterminado (dbo).
Sidewinder94
19

use el siguiente comando después de eliminar todas las filas de esa tabla mediante la instrucción delete

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

EDITAR: sintaxis corregida para SQL Server

abdelwahed
fuente
99
TRUNCATEevita el registro y es considerablemente más rápido que DELETEpara tablas grandes. Como tal, esta no es una verdadera solución equivalente.
siride
1
¿Cómo es esta respuesta diferente de la que se dio un año antes?
Ofer Zelig
17

Bueno, como no encontré ejemplos de la solución muy simple que utilicé, que es:

  1. Suelta la clave foránea;
  2. Truncar tabla
  3. Recrea la clave foránea

Aquí va:

1) Encuentre el nombre de la clave externa que está causando la falla (por ejemplo: FK_PROBLEM_REASON, con el campo ID, de la tabla TABLE_OWNING_CONSTRAINT) 2) Elimine esa clave de la tabla:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Truncar tabla deseada

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Vuelva a agregar la clave a esa primera tabla:

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

Eso es.

Lauro Wolff Valente Sobrinho
fuente
Esto no funciona si tiene varias tablas con referencias de clave externa. Tendría que eliminar muchas restricciones de claves foráneas en toda la base de datos.
jbright
13

Aquí hay un script que escribí para automatizar el proceso. Espero que ayude.

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'
denver_citizen
fuente
2
Ten cuidado. También agregaría acciones referenciales en las teclas de su script o perderá la configuración en cascada.
alphadogg el
1
esto no funcionó para mí, pero me gustó su espíritu, así que modifiqué algunas cosas: lo convertí en un procedimiento almacenado, cambié la forma en que se llenan las claves externas y recreé el script original trunca todas las tablas referenciadas, esto puede ser incorrecto cuando se hace referencia la tabla no se puede truncar porque también tiene referencias de clave externa. En esta versión, solo la tabla especificada como parámetro se truncará, toda la tabla referenciada se debe truncar manualmente antes de llamar a este script. Publiqué la actualización de este hilo aquí stackoverflow.com/a/13249209/157591
Peter Szanto
1
@alphadogg ¿Hay alguna forma de encontrar esas acciones referenciales? He estado hurgando en Internet y parece que no puedo encontrarlos. Puedo publicarlo como una pregunta formal, si prefieres.
Michael - ¿Dónde está Clay Shirky
1
Nota para futuros visitantes: está en la sys.foreign_keystabla. ( Referencia )
Michael - ¿Dónde está Clay Shirky?
@Michael: También puede usar INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/library/ms179987.aspx )
alphadogg
13

puede seguir este paso, reseeding tablepuede eliminar los datos de la tabla.

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

Si aparece algún error, debe reiniciar la tabla principal.

Rajneesh Kumar
fuente
1
Tenga en cuenta que aunque esto funcione bien, el registro de transacciones aumentará en la cantidad de registros en la tabla frente a 'tabla truncada' que solo coloca un registro en el registro de transacciones. No es un gran problema para la mayoría de las tablas, pero si hay millones + filas, entonces podría ser un problema.
David
9
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;
Victor Jiménez
fuente
8
Esta pregunta es sobre MS SQL Server, que no tiene una configuración
FOREIGN_KEY_CHECKS
1
Creo que esto funcionaría desde MySQL, pero no desde MS SQL Server
Cocowalla
8

Si entiendo correctamente, lo que desea hacer es tener un entorno limpio para configurar la base de datos que implique pruebas de integración.

Mi enfoque aquí sería dejar caer todo el esquema y recrearlo más tarde.

Razones:

  1. Probablemente ya tenga una secuencia de comandos "crear esquema". Reutilizarlo para el aislamiento de prueba es fácil.
  2. Crear un esquema es bastante rápido.
  3. Con ese enfoque, es bastante fácil configurar su script para que cada dispositivo cree un NUEVO esquema (con un nombre temporal), y luego puede comenzar a ejecutar dispositivos de prueba en paralelo, haciendo que la parte más lenta de su conjunto de pruebas sea mucho más rápido .
Ken Egozi
fuente
1
Me gustaría 'truncar' todo el esquema, no soltarlo. Me gustaría hacerlo en el método de configuración de las pruebas de integración. Llamar al script de creación de base de datos desde las pruebas de integración ... no es la primera solución a la que recurriré.
ripper234
7

Encontrado en otra parte de la 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'
Freddie Bell
fuente
3
Probablemente debería ser 'ALTER TABLE? CON CHECK CHECK CONSTRAINT ALL '.
Andriy M
20
-1: Acabo de confirmar que esto no funciona en absoluto con el comando truncar como se pregunta en la pregunta. Ver stackoverflow.com/questions/3843806/…
Lynn Crumbling
7

No puede truncar una tabla si no elimina las restricciones. Una desactivación tampoco funciona. necesitas dejarlo todo. Hice un script que elimina todas las restricciones y luego lo recrea.

Asegúrese de envolverlo en una transacción;)

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
renanleandrof
fuente
6

Las respuestas de @denver_citizen y @Peter Szanto no funcionaron para mí, pero las modifiqué para tener en cuenta:

  1. Claves compuestas
  2. En acciones Eliminar y Actualizar
  3. Verificación del índice al volver a agregar
  4. Esquemas distintos de dbo
  5. Múltiples mesas a la vez
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;
GhotiPhud
fuente
4

truncar no funcionó para mí, eliminar + volver a colocar es la mejor salida. En caso de que haya algunos de ustedes que necesiten iterar sobre una gran cantidad de tablas para realizar la eliminación + reposición, es posible que se encuentren problemas con algunas tablas que no tienen una columna de identidad, el siguiente código verifica si existe una columna de identidad antes de intentar volver a sembrar

    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
Ji_in_coding
fuente
4

Escribí las siguientes formas y traté de parametrizarlas, para que pueda Ejecutarlas en un Query documentO Haga que sea útil SPcon ellas fácilmente .

A) Eliminar

Si su tabla no tiene millones de registros, esto funciona bien y no tiene ningún 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)
  • En la respuesta anterior mía, el método para resolver el problema mencionado en la pregunta se basa en la respuesta @ s15199d .

B) Truncar

Si su tabla tiene millones de registros o no tiene ningún problema con el comando Alter en sus códigos, use este:

--   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
  • En la respuesta anterior mía, el método para resolver el problema mencionado en la pregunta se basa en la respuesta @LauroWolffValenteSobrinho .

  • Si tiene más de una RESTRICCIÓN, entonces debe agregar sus códigos como yo a la consulta anterior

  • También puede cambiar la base de código anterior @SerjSagan answer para deshabilitar y habilitar la restricción

RAM
fuente
3

Es mi solución a este problema. Lo usé para alterar PK, pero la idea es la misma. Espero que esto sea útil)

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'
Oleg
fuente
3

Para MS SQL, al menos, las versiones más nuevas, puede deshabilitar las restricciones con un código como este:

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
Serj Sagan
fuente
Creo que establecimos anteriormente que esto no funciona. Tal vez lo hace para las nuevas versiones?
Coops
2
Fwiw, esto no funciona en la versión del OP (2005), y tampoco funciona en su sucesor (MSSQL2008).
CB
3

Lo siguiente funciona para mí incluso con restricciones FK, y combina las siguientes respuestas para descartar solo las tablas especificadas :


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:

Creo que todavía ayuda declarar las tablas en el orden en que desea que se eliminen (es decir, eliminar dependencias primero). Como se ve en esta respuesta , en lugar de nombres específicos de bucle, podría sustituir todas las tablas con

EXEC sp_MSForEachTable 'DELETE FROM ?; DBCC CHECKIDENT (''?'',RESEED, 0);';
drzaus
fuente
Realmente no intenté con otros scripts ya que todos declararon que no funcionan cuando tienes claves externas. Así que probé este y este me funcionó.
Vivendi
1
DELETE No es lo mismo que TRUNCATE. Esto llenará sus registros de transacciones.
Dan Bechard el
@ Dan, probablemente un buen punto; como he mencionado que sólo juntos las otras respuestas por aquí ...
drzaus
@drzaus Funcionará bien para tablas pequeñas / medianas, pero un servidor SQL de producción se desconectó debido a un comando de eliminación que llenaba el registro de transacciones, que llenaba el disco duro. Como mínimo, asegúrese de que sus registros de transacciones tengan un tamaño máximo antes de intentarlo en una tabla grande.
Dan Bechard el
2

Si ninguna de estas respuestas funcionó como en mi caso, haga esto:

  1. Restricciones de caída
  2. Establecer todos los valores para permitir nulos
  3. Truncar tabla
  4. Agregar restricciones que se descartaron.

¡Buena suerte!

G Jeny Ramirez
fuente
alguna muestra sql al respecto?
Kiquenet
2

Eliminar y luego restablecer el incremento automático:

delete from tablename;

entonces

ALTER TABLE tablename AUTO_INCREMENT = 1;
mwafi
fuente
Gracias, esto funcionó bien.
Sr. Polywhirl
1

La única forma es soltar claves foráneas antes de truncar. Y después de truncar los datos, debe volver a crear los índices.

El siguiente script genera el SQL requerido para eliminar todas las restricciones de clave externa.

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

A continuación, el siguiente script genera el SQL requerido para volver a crear claves foráneas.

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

Ejecute el script generado para eliminar todas las claves foráneas, truncar tablas y luego ejecute el script generado para volver a crear todas las claves foráneas.

Las consultas se toman desde aquí .

Ehsan Mirsaeedi
fuente
0

En SSMS tuve un diagrama abierto que muestra la clave. Después de eliminar la clave y truncar el archivo, actualicé y luego volví a enfocarme en el diagrama y creé una actualización al borrar y restaurar un cuadro de identidad. Al guardar el Diagrama, apareció un cuadro de diálogo Guardar, que un cuadro de diálogo "Se realizaron cambios en la base de datos mientras trabajaba", al hacer clic en Sí, se restauró la Clave y se restauró de la copia enganchada en el Diagrama.

usuario2584621
fuente
0

Si está haciendo esto en cualquier tipo de frecuencia, diablos, incluso en un horario, absolutamente, inequívocamente, nunca usaría una declaración DML. El costo de escribir en el registro de transacciones es demasiado alto, y configurar toda la base de datos en SIMPLEmodo de recuperación para truncar una tabla es ridículo.

La mejor manera, desafortunadamente, es la forma difícil o laboriosa. Ese ser:

  • Restricciones de caída
  • Truncar tabla
  • Volver a crear restricciones

Mi proceso para hacer esto implica los siguientes pasos:

  1. En SSMS, haga clic con el botón derecho en la tabla en cuestión y seleccione Ver dependencias
  2. Tome nota de las tablas a las que se hace referencia (si las hay)
  3. De vuelta en el explorador de objetos, expanda el nodo Claves y tome nota de las claves externas (si las hay)
  4. Iniciar scripting (soltar / truncar / volver a crear)

Guiones de esta naturaleza deben hacerse dentro de una begin trany de commit tranbloque.

pimbrouwers
fuente
-3

Me acabo de dar cuenta de que puede usar la tabla TRUNCATE en una tabla primaria con restricciones de clave externa en un elemento secundario siempre que DESACTIVE las restricciones en la tabla secundaria primero. P.ej

Clave externa CONSTRAINT child_par_ref en la tabla secundaria, referencias 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;
PWF
fuente
1
Esta no es una sintaxis válida de SQL Server para ALTER TABLE. No hay {ENABLE | DESACTIVAR} RESTRICCIÓN. Ver: msdn.microsoft.com/en-us/library/ms190273.aspx
jason_ruz
-3

La forma más fácil:
1 - Ingresar en phpmyadmin
2 - Hacer clic en el nombre de la tabla en la columna izquierda
3 - Hacer clic en Operación (menú superior)
4 - Hacer clic en "Vaciar la tabla (TRUNCATE)
5 - Desactivar cuadro" Habilitar comprobaciones de clave externa "
6 - Listo !

Enlace al tutorial de imagen
Tutorial: http://www.imageno.com/wz6gv1wuqajrpic.html
(lo siento, no tengo suficiente reputación para cargar imágenes aquí: P)

Marco
fuente
2
OP declaró MSSQL. Diste una respuesta exclusiva de MySQL.
reformado el
-4

Podrías intentarlo DELETE FROM <your table >;.

El servidor le mostrará el nombre de la restricción y la tabla, y al eliminar esa tabla puede eliminar lo que necesita.

René
fuente
66
Lea su segunda frase sobre la pregunta. Sabe que puede hacer eso, pero eso no es lo que quiere
renanleandrof
-7
SET FOREIGN_KEY_CHECKS=0;
TRUNCATE table1;
TRUNCATE table2;
SET FOREIGN_KEY_CHECKS=1;

referencia - truncar tabla restringida de clave externa

Trabajando para mí en MYSQL

JackSparrow
fuente
1
Aparte de la versión especificada, ¿hay algo más malo con esto? ¿Se recomendaría usarlo o evitarlo por completo?
Andy Ibáñez
1
@AndyIbanez MySQL es un producto completamente diferente de MSSQL, no una versión diferente de MSSQL.
Dan Bechard
1
es la respuesta correcta No sé por qué todos dan negativo
sunil