2012-10-04 150 views
13

Quiero escribir el comando sql para eliminar todas las restricciones en todas las tablas. Busqué en Internet y encontré lo siguiente que funciona bien si la base de datos es pequeña y no compleja.¿Cómo se eliminan todas las restricciones de clave externa en todas las tablas?

DECLARE @name VARCHAR(128) 
DECLARE @constraint VARCHAR(254) 
DECLARE @SQL VARCHAR(254) 
DECLARE @schema VARCHAR(128) 

SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME) 
SELECT @schema = (SELECT TOP 1 schema_name(schema_id) FROM sys.objects WHERE [name] = @name) 

WHILE @name is not null 
BEGIN 
    SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME) 
    WHILE @constraint IS NOT NULL 
    BEGIN 
     SELECT @SQL = 'ALTER TABLE ' + @schema + '.[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']' 
     EXEC (@SQL) 
     PRINT 'Dropped FK Constraint: ' + @constraint + ' on ' + @name 
     SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME) 
    END 
SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME) 
SELECT @schema = (SELECT TOP 1 schema_name(schema_id) FROM sys.objects WHERE [name] = @name) 
END 
GO 

No funciona si funciono con una base de datos más complejo o incluso AdventureWork. Muestra algunos errores como a continuación.

Msg 3728, Level 16, State 1, Line 1 
'FK_ap_invoice_modification_type_id' is not a constraint. 
Msg 3727, Level 16, State 0, Line 1 
Could not drop constraint. See previous errors. 
Msg 3725, Level 16, State 0, Line 1 
The constraint 'PK_ap_invoice' is being referenced by table '_drop_now_ap_invoice_detail', foreign key constraint 'FK_ap_invoice_detail_ap_invoice'. 
Msg 3727, Level 16, State 0, Line 1 
Could not drop constraint. See previous errors. 

La razón es porque algunos FK se mencionan en otra tabla. Tengo que ejecutar este script un par de veces hasta que la base de datos esté limpia.

Quiero saber cómo puedo borrar todas las claves ajenas en la base de datos.

+1

De acuerdo con el título quieres eliminar claves foráneas Pero su última pregunta pide un "claro todo", incluyendo tablas, procedimientos almacenados, funciones. ¿Que quieres decir con eso? – Yaroslav

+0

@Yaroslav Gracias por señalar. Estoy a plena carga con las tareas. Acabo de actualizar los detalles de mi pregunta para que coincida con el título. – Anonymous

+0

Aunque estoy seguro, debe haber verificado si tiene preguntas similares, pero le pediría que revise la solución aquí: http://stackoverflow.com/a/1438933/1268844 – Anshu

Respuesta

23

Existe mucha información sobre el tema a su alrededor. Compruebe this detailed answer por @AaronBertrand. Habla de la desactivación temporal de las claves externas, pero al leerlo todo y modificar a voluntad tendrá un buen script para jugar y lograr mucho.

Por mi parte puedo proponer 2 secuencias de comandos diferentes para obtener todas las claves externas. En ambos casos, elimine el comentario del --EXEC (@SQL) para ejecutar su código ALTER. O puede esperar hasta que imprima todas las cláusulas alternativas y luego copiar pegar para ejecutarlas.

primero utiliza la INFORMATION_SCHEMA para obtener las restricciones:

DECLARE @SQL VARCHAR(MAX)='' 
SELECT @SQL = @SQL + 'ALTER TABLE ' + QUOTENAME(FK.TABLE_SCHEMA) + '.' + QUOTENAME(FK.TABLE_NAME) + ' DROP CONSTRAINT [' + RTRIM(C.CONSTRAINT_NAME) +'];' + CHAR(13) 
--SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME 
    FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C 
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK 
    ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME 
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK 
    ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME 
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU 
    ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME 
INNER JOIN (
      SELECT i1.TABLE_NAME, i2.COLUMN_NAME 
       FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 
      INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 
       ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME 
      WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' 
      ) PT 
    ON PT.TABLE_NAME = PK.TABLE_NAME 

--EXEC (@SQL) 

PRINT @SQL 

Ésta utilizando diferentes vistas del sistema y una tabla CTE.

DECLARE @SQL varchar(4000)='' 
;WITH ReferencingFK AS 
(
    SELECT fk.Name AS 'FKName', OBJECT_NAME(fk.parent_object_id) 'ParentTable', 
      cpa.name 'ParentColumnName', OBJECT_NAME(fk.referenced_object_id) 'ReferencedTable', 
      cref.name 'ReferencedColumnName' 
    FROM sys.foreign_keys fk 
    INNER JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id 
    INNER JOIN sys.columns cpa ON fkc.parent_object_id = cpa.object_id AND fkc.parent_column_id = cpa.column_id 
    INNER JOIN sys.columns cref ON fkc.referenced_object_id = cref.object_id AND fkc.referenced_column_id = cref.column_id 
) 
SELECT @SQL = @SQL + 'ALTER TABLE ' + ParentTable + ' DROP CONSTRAINT [' + RTRIM(FKName) +'];' + CHAR(13) 
--SELECT FKName, ParentTable, ParentColumnName, ReferencedTable, ReferencedColumnName 
    FROM ReferencingFK 
WHERE ReferencedTable = 'Employee' 
ORDER BY ParentTable, ReferencedTable, FKName 

--EXEC (@SQL) 

PRINT @SQL 
+1

Debe usar 'varchar (max)' y ''ALTER TABLE' + QUOTENAME (FK.TABLE_SCHEMA) + '.' + QUOTENAME (FK.TABLE_NAME) + ''para evitar errores de sintaxis. –

+0

Añadido @AntoineAubry, thx – Yaroslav

5

variante más sencilla:

DECLARE @sql nvarchar(MAX) 
SET @sql = '' 

SELECT @sql = @sql + 'ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA) 
    + '.' + QUOTENAME(KCU1.TABLE_NAME) 
    + ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) + '; ' 
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1 
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG 
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 


-- PRINT @sql 
EXECUTE(@sql) 
6

He mejorado la primera secuencia de comandos proporcionada por @Yaroslav y la secuencia de comandos proporcionada por @Quandary por lo que ahora trabaja para bases de datos cuya consulta SQL para dejar todas las llaves extranjeras uno por uno excede el tamaño asignado para la variable SQL (4000 o MAX caracteres).

Las secuencias de comandos alteradas dejan 5 claves foráneas por iteración (para estar seguro, implementado agregando TOP 5). Los scripts se detienen cuando no queda ninguna clave externa para soltar (la variable SQL permanece vacía después de ejecutar SELECT).

primer guión de @Yaroslav

DECLARE @SQL varchar(4000) 
IterationStart: 
SET @SQL='' 
SELECT TOP 5 @SQL = @SQL + 'ALTER TABLE ' + FK.TABLE_NAME + ' DROP CONSTRAINT [' + RTRIM(C.CONSTRAINT_NAME) +'];' + CHAR(13) 
    FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C 
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK 
    ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME 
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK 
    ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME 
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU 
    ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME 
INNER JOIN (
      SELECT i1.TABLE_NAME, i2.COLUMN_NAME 
       FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 
      INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 
       ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME 
      WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' 
      ) PT 
    ON PT.TABLE_NAME = PK.TABLE_NAME 
IF @SQL <> '' 
BEGIN 
    EXEC(@SQL) 
    GOTO IterationStart 
END 

Script de @Quandary

DECLARE @sql nvarchar(MAX) 

IterationStart: 
SET @sql = '' 

SELECT TOP 5 @sql = @sql + 'ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA) 
    + '.' + QUOTENAME(KCU1.TABLE_NAME) 
    + ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) + '; ' 
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1 
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG 
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 

IF @SQL <> '' 
BEGIN 
    EXEC(@SQL) 
    GOTO IterationStart 
END 
1

que utiliza la solución INFORMATION_SCHEMA mencionado por @Yaroslav, pero tuvo demasiadas constantes de clave externa en mi base de datos para que encajen todo en un varchar (MAX). Así que tuve que modificar el script para usar una tabla temporal y un cursor en su lugar.

Además, añadí [] alrededor del nombre de la tabla.

DECLARE @SQL TABLE (Command VARCHAR(MAX)) 

INSERT @SQL 
SELECT 'ALTER TABLE [' + FK.TABLE_NAME + '] DROP CONSTRAINT [' + RTRIM(C.CONSTRAINT_NAME) +'];' + CHAR(13) 
    FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C 
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK 
    ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME 
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK 
    ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME 
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU 
    ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME 
INNER JOIN (
      SELECT i1.TABLE_NAME, i2.COLUMN_NAME 
       FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 
      INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 
       ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME 
      WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' 
      ) PT 
    ON PT.TABLE_NAME = PK.TABLE_NAME 

DECLARE cmdCursor CURSOR 
    FOR SELECT Command FROM @SQL 
OPEN cmdCursor 
DECLARE @Command VARCHAR(MAX) 

FETCH NEXT FROM cmdCursor INTO @Command 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    PRINT @Command 
    EXEC (@Command) 
    FETCH NEXT FROM cmdCursor INTO @Command 
END 

CLOSE cmdCursor; 
DEALLOCATE cmdCursor; 
1
CREATE TABLE #Commands (Command VARCHAR(MAX)) 

INSERT #Commands 
SELECT 'ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA) 
    + '.' + QUOTENAME(KCU1.TABLE_NAME) 
    + ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) + '; ' 
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1 
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG 
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 
WHERE ORDINAL_POSITION=1 

--SELECT * FROM #Commands 

DECLARE @Command VARCHAR(MAX) 
DECLARE curCommand CURSOR FOR 
SELECT Command FROM #Commands 

OPEN curCommand 

FETCH NEXT FROM curCommand INTO @Command 

WHILE @@FETCH_STATUS =0 
BEGIN 

    EXEC(@Command) 
    FETCH NEXT FROM curCommand INTO @Command 

END 

CLOSE curCommand 
DEALLOCATE curCommand 

DROP TABLE #Commands 
+2

Si bien este código puede responder a la pregunta, proporcionar un contexto adicional con respecto a por qué y/o cómo responde este código a la pregunta mejora su valor a largo plazo. – NathanOliver

+0

Para bases de datos con muchas limitaciones, otras soluciones mencionadas fallaron, pero esta funcionó para mí. – JCallico

2

Aquí hay un guión corto y dulce que utilizo (en SQL Server 2008 en adelante) para eliminar todas las claves externas que también tiene en cuenta el esquema del objeto:

declare @sql varchar(max) = (
    select 
     'alter table ' + quotename(schema_name(schema_id)) + '.' + 
     quotename(object_name(parent_object_id)) + 
     ' drop constraint '+quotename(name) + ';' 
    from sys.foreign_keys 
    for xml path('') 
); 
exec sp_executesql @sql; 
+0

¡Gran pequeño truco! – Takarii

Cuestiones relacionadas