2010-10-02 25 views
22

Tengo una tabla llamada PX_Child que tiene una clave externa en PX_Parent. Me gustaría desactivar temporalmente esta restricción FK para poder truncar PX_Parent. No estoy seguro de cómo va esto sin embargo.Al desactivar la restricción de clave externa, ¿aún no se puede truncar la tabla? (SQL Server 2005)

que he probado estos comandos

ALTER TABLE PX_Child NOCHECK CONSTRAINT ALL 

ALTER TABLE PX_Parent NOCHECK CONSTRAINT ALL 

(truncate commands) 

ALTER TABLE PX_Child CHECK CONSTRAINT ALL 

ALTER TABLE PX_Parent CHECK CONSTRAINT ALL 

Pero el truncado todavía me dice que no puede truncar PX_Parent debido a una restricción de clave externa. Miré alrededor de la red y parece que no puedo encontrar lo que estoy haciendo mal, lo siento por la naturaleza básica de esta pregunta.

+1

Parece que Kalen Delaney fue inadvertidamente responsable de iniciar esta idea fuera. [Aquí se aclara] (http://www.eggheadcafe.com/software/aspnet/29927698/cant-truncate-table.aspx) "hay que quitar la restricción de referencia con el fin de truncar la tabla." –

Respuesta

31

No se puede truncar la tabla si hay alguna clave foránea referencia a ella, incluyendo las limitaciones de movilidad reducida. Debe eliminar las restricciones de clave externa o usar el comando DELETE.

+1

Véase mi respuesta (5 años más tarde) por debajo de la forma de generar rápidamente el '' DROP CONSTRAINT' y ADD CONSTRAINT' SQL – RJB

5

servidor SQL no le permite truncar la tabla, mientras que existe la restricción, incluso si está desactivado. Elimine la restricción y vuelva a crearla después de truncar la tabla. O simplemente suelte y vuelva a crear las tablas, lo que sea más fácil de hacer en su aplicación.

+2

¿Qué quiere decir que no es un comando transaccional? Puedes enrollarlo bien. 'CREATE TABLE Blah (a int); INSERT Blah VALUES (1); SELECCIONAR * FROM Blah; COMIENZA TRAN; TABLA TRUNCATE Blah; SELECCIONAR * FROM Blah; ROLLBACK TRAN SELECT * FROM Blah; DROP TABLE Blah'. Truncar funciona al desasignar páginas enteras en lugar de eliminar filas, pero sigue siendo transaccional. – ErikE

+0

@Emtucifor: ¡Ups, parece que malinterpreté la documentación de que tienes razón! Eliminé esa información errónea. –

+0

@Emtucifor, @pgroke, de manera que ambos estén en lo correcto, ya que el estándar permite que TRUNCATE sea no transaccional, pero las implementaciones pueden realizar transacciones. Por lo tanto, TRUNCATE tal como se define no promete que se puede realizar una reversión, pero SqlServer (y Postgres) agrega esa promesa más allá del estándar. –

10

hay una manera más fácil-ish. Me encontré con el mismo problema y encontré esta solución: https://www.mssqltips.com/sqlservertip/3347/drop-and-recreate-all-foreign-key-constraints-in-sql-server/

Si sólo ejecuta esta consulta en su base de datos, se generará el T-SQL es necesario incluir antes/después de su procedimiento almacenado, con el fin de eliminar y luego restaure cualquier restricción de clave externa.

No se preocupe por tratar de entender esta consulta en sí.

CREATE TABLE #x -- feel free to use a permanent table 
(
    drop_script NVARCHAR(MAX), 
    create_script NVARCHAR(MAX) 
); 

DECLARE @drop NVARCHAR(MAX) = N'', 
     @create NVARCHAR(MAX) = N''; 

-- drop is easy, just build a simple concatenated list from sys.foreign_keys: 
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]; 

INSERT #x(drop_script) SELECT @drop; 

-- create is a little more complex. We need to generate the list of 
-- columns on both sides of the constraint, even though in most cases 
-- there is only one column. 
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; 

UPDATE #x SET create_script = @create; 

PRINT @drop; 
PRINT @create; 

/* 
EXEC sp_executesql @drop 
-- clear out data etc. here 
EXEC sp_executesql @create; 
*/ 

Genera un montón de:

ALTER TABLE [dbo].[Whatever] DROP CONSTRAINT.... 
-- 
ALTER TABLE [dbo].[Whatever] ADD CONSTRAINT.... 
+6

mal consejo: "No te preocupes por tratar de entender esta consulta en sí". Nunca ejecute nada que haya salido de la red sin entenderlo –

+0

Es cierto, pero no era una versión de producción del DB – RJB

+2

. Hay una diferencia entre entender cómo funciona una consulta y asegurarse de que no hará ningún daño. Esto último es casi siempre más fácil. – wolfrevokcats

Cuestiones relacionadas