2012-03-23 24 views
8

Ho circa 100 tabelle in cui tutte hanno vincoli di chiave esterna duplicati su di esse.eliminazione di chiavi esterne duplicate

C'è un modo per liberarmene? C'è una query che potrebbe darmi tutte le chiavi duplicate in esso?

risposta

10

Qui sto utilizzando questo script T-SQL per rilevare i vincoli FK potenzialmente duplicati e inoltre produce le necessarie istruzioni ALTER TABLE...DROP CONSTRAINT nell'ultima colonna di output.

Non è possibile rilevare e scegliere in modo affidabile quale dei vincoli FK multipli da rilasciare, quindi in pratica non è possibile individuarli e quindi selezionare manualmente quelli da eliminare (utilizzando l'istruzione drop prodotta dalla query).

;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

eccellente GRAZIE !! – peter

+0

c'è un modo per ottenere anche il nome dello schema? poiché ce ne sono pochi che non appartengono a Dbo Scheme. ! – peter

+1

@Peter: ** ** SICURO aggiornato la mia risposta per includere lo schema genitore (si potrebbe ottenere lo schema di riferimento, anche, se necessario - ma non è necessario che per l'istruzione DROP) –

2

Per un 100 tavoli non è un'opzione, ma se si dispone di pochi tavoli, creare un diagramma in SQL Server Management Studio, aggiungere le tabelle lì ed eliminare i doppioni visivamente.

0

Ciò elimina la più recente creato duplicati

;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 
Problemi correlati