2012-03-23 42 views
8

Tengo aproximadamente 100 tablas en las que todas tienen restricciones duplicadas de clave externa.descartar claves externas duplicadas

¿Hay alguna manera de que pueda deshacerme de él? ¿Hay alguna consulta que pueda darme todas las claves duplicadas?

Respuesta

10

Estoy usando este script T-SQL aquí para detectar posibles restricciones duplicadas de FK, y también produce las declaraciones necesarias ALTER TABLE...DROP CONSTRAINT en la última de las columnas de salida.

No se puede detectar de manera confiable y elegir cuál de las múltiples restricciones de FK para descartar, por lo que básicamente se deja detectarlas y luego se seleccionan manualmente las que se desecharán (usando esa declaración de caída producida por mi consulta).

;WITH FKData AS 
(
    SELECT 
     fk.parent_object_id, 
     fkc.parent_column_id, 
     fk.referenced_object_id, 
     fkc.referenced_column_id, 
     FKCount = COUNT(*) 
    FROM 
     sys.foreign_keys fk 
    INNER JOIN 
     sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id 
    GROUP BY 
     fk.parent_object_id, fkc.parent_column_id, fk.referenced_object_id, fkc.referenced_column_id 
    HAVING 
     COUNT(*) > 1 
), 
DuplicateFK AS 
(
    SELECT 
     FKName = fk.Name, 
      ParentSchema = s1.Name, 
     ParentTable = t1.Name, 
     ParentColumn = c1.Name, 
     ReferencedTable = t2.Name, 
     ReferencedColumn = c2.Name 
    FROM 
     sys.foreign_keys fk 
    INNER JOIN 
     sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id 
    INNER JOIN 
     FKData f ON fk.parent_object_id = f.parent_object_id 
       AND fk.referenced_object_id = f.referenced_object_id 
       AND fkc.parent_column_id = f.parent_column_id 
       AND fkc.referenced_column_id = f.referenced_column_id 
    INNER JOIN 
     sys.tables t1 ON f.parent_object_id = t1.object_id 
    INNER JOIN 
     sys.columns c1 ON f.parent_object_id = c1.object_id AND f.parent_column_id = c1.column_id 
INNER JOIN 
    sys.schemas s1 ON t1.schema_id = s1.schema_id 
    INNER JOIN 
     sys.tables t2 ON f.referenced_object_id = t2.object_id 
    INNER JOIN 
     sys.columns c2 ON f.referenced_object_id = c2.object_id AND f.referenced_column_id = c2.column_id 
) 
SELECT 
    FKName, 
    ParentSchema, ParentTable, ParentColumn, 
    ReferencedTable, ReferencedColumn, 
    DropStmt = 'ALTER TABLE ' + ParentSchema + '.' + ParentTable + 
       ' DROP CONSTRAINT ' + FKName 
FROM 
    DuplicateFK 
+0

excelente gracias !! – peter

+0

¿hay alguna manera de que podamos obtener el nombre del esquema también? ya que hay pocos que no pertenecen al esquema dbo. – peter

+1

@Peter: ** SURE! ** actualizó mi respuesta para incluir el esquema principal (también podría obtener el esquema referenciado, si es necesario, pero no necesita eso para la declaración DROP) –

2

Por unos 100 mesas que no es una opción, pero si usted tiene sólo unas pocas mesas, crear un diagrama en SQL Server Management Studio, añadir sus mesas allí y eliminar los duplicados visualmente.

0

Esto elimina los duplicados de más reciente creación

;WITH fkeys AS (
SELECT f.object_id , 
     f.name , 
     f.parent_object_id, 
     ROW_NUMBER() OVER(PARTITION BY t.column_names ORDER BY f.create_date,f.[object_id]) AS RowNum 
FROM sys.foreign_keys f 
     CROSS APPLY (SELECT fc.parent_object_id,parent_column_id,fc.referenced_object_id ,fc.referenced_column_id 
         FROM  sys.foreign_key_columns fc 
         WHERE  fc.constraint_object_id = f.object_id 
         ORDER BY constraint_column_id 
        FOR XML PATH('') 
        ) t (column_names) 
) 
SELECT 'ALTER TABLE '+QUOTENAME(OBJECT_SCHEMA_NAME(f.parent_object_id)) + '.'+QUOTENAME(OBJECT_NAME(f.parent_object_id)) +' DROP CONSTRAINT '+QUOTENAME(f.name)+';' AS DropStatement 
FROM fkeys f 
WHERE f.RowNum >= 2 
Cuestiones relacionadas