2012-03-23 17 views
8

Ich habe etwa 100 Tabellen, wo alle doppelte Fremdschlüssel Einschränkungen für sie haben.löschen doppelte Fremdschlüssel

Gibt es einen Weg, wie ich es loswerden könnte? Gibt es eine Abfrage, die mir alle doppelten Schlüssel geben könnte?

Antwort

10

Ich verwende dieses T-SQL-Skript hier, um potenziell doppelte FK-Einschränkungen zu erkennen - und es erzeugt auch die notwendigen ALTER TABLE...DROP CONSTRAINT-Anweisungen in der letzten der Ausgabespalten.

Sie können nicht zuverlässig automatisch erkennen und auswählen, welche von mehreren FK-Abhängigkeiten fallen gelassen werden. Sie müssen sie also im Grunde erkennen und dann manuell auswählen, welche fallen gelassen werden sollen (mithilfe der von meiner Abfrage erstellten drop-Anweisung).

;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

Excellent Danke !! – peter

+0

gibt es eine Möglichkeit, wie wir den Schemanamen auch bekommen könnten? da es einige gibt, die nicht zum dbo schema gehören. – peter

+1

@Peter: ** SURE! ** aktualisierte meine Antwort, um das Elternschema einzuschließen (Sie könnten auch das referenzierte Schema erhalten, wenn nötig - aber Sie brauchen das nicht für die DROP-Anweisung) –

2

für eine 100-Tabellen ist es keine Option, aber wenn man nur ein paar Tische haben, ein Diagramm, in dem SQL Server Management Studio erstellen, Ihre Tabellen dort hinzufügen und die Betrogenen visuell löschen.

0

Dies entfernt die zuletzt erstellten Duplikate

;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 
Verwandte Themen