Come trovare le dipendenze delle chiavi esterne in SQL Server?


163

Come posso trovare tutte le dipendenze delle chiavi esterne su una determinata colonna?

Quali sono le diverse alternative (graficamente in SSMS, query / viste in SQL Server, strumenti di database di terze parti, codice in .NET)?

Risposte:


290

La seguente query ti aiuterà a iniziare. Elenca tutte le relazioni di chiave esterna all'interno del database corrente.

SELECT
    FK_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

È inoltre possibile visualizzare graficamente le relazioni all'interno dello studio SQL Server Management in Diagrammi database.


8
Grazie! Ho solo bisogno di aggiungere << WHERE FK.TABLE_NAME = 'MyTable' AND CU.COLUMN_NAME = 'MyColumn' >> per ottenere la colonna specifica.
Anche Mien il

1
+1! E se necessario per ottenere la colonna specifica, ma per tutte le tabelle, farebbe "WHERE CU.COLUMN_NAME = 'MyColumn'".
liang

1
Simile a Even - ho usato WHERE PK.TABLE_NAME = 'MyTable' per trovare la tabella da cui dipendeva.
Lanceomagnifico

7
@samkitshah: nessuno ha detto che lo avrebbe fatto. La domanda è taggata sql-server, che per definizione è la tecnologia Microsoft. Postgres non ha nulla a che fare con questo.
Neolisk,

2
-1: in questa query mancano le chiavi esterne supportate da un vincolo univoco o da un indice univoco, anziché da una chiave primaria, nella tabella di riferimento. Per MSDN : “Un vincolo di chiave esterna non deve essere collegato solo a un vincolo di chiave primaria in un'altra tabella; può anche essere definito per fare riferimento alle colonne di un vincolo UNIQUE in un'altra tabella. " La risposta può essere fatta funzionare con vincoli univoci rimuovendo l'ultimo join e con indici univoci rimuovendo gli ultimi due join, ma ciò limita le informazioni restituite.
Douglas,

100

provare: sp_help [table_name]

otterrai tutte le informazioni sulla tabella, comprese tutte le chiavi esterne


2
bello, molto utile. Più memorabile della risposta contrassegnata! non riesco a credere che non puoi vederli solo negli sms!
JonnyRaa,

4
Molto bene, grazie. Ma per cercare gli FK, preferisco l'output della risposta di Michael qui sotto: sp_fkeys [table]
AjV Jsy

.... o se non ottieni risultati da questo (ma sp_help mostra chiavi esterne), la versione più completa può aiutare:sp_fkeys @fktable_name='TableName'
AjV Jsy,

superba! breve e conciso!
zeroflaw,

39

Se prevedi di eliminare o rinominare una tabella o una colonna, trovare solo dipendenze di chiavi esterne potrebbe non essere sufficiente.

Tabelle di riferimento non connesse con chiave esterna - Dovrai anche cercare tabelle di riferimento che potrebbero non essere connesse con chiave esterna (ho visto molti database con design errato che non avevano chiavi esterne definite ma che avevano dati correlati ). La soluzione potrebbe essere quella di cercare il nome della colonna in tutte le tabelle e cercare colonne simili.

Altri oggetti di database - questo è probabilmente un po 'fuori tema, ma se stavi cercando tutti i riferimenti di quanto sia anche importante verificare la presenza di oggetti dipendenti.

Strumenti della GUI: prova l'opzione "Trova oggetti correlati" di SSMS o strumenti come Ricerca ApexSQL (strumento gratuito, integra in SSMS) per identificare tutti gli oggetti dipendenti, comprese le tabelle connesse con chiave esterna.


39

Poiché la tua domanda è orientata verso una singola tabella, puoi utilizzare questo:

EXEC sp_fkeys 'TableName'

L'ho trovato su SO qui:

https://stackoverflow.com/a/12956348/652519

Ho trovato le informazioni di cui avevo bisogno abbastanza rapidamente. Elenca la tabella, la colonna e il nome della chiave esterna.

MODIFICARE

Ecco un link alla documentazione che descrive in dettaglio i diversi parametri che possono essere utilizzati: https://docs.microsoft.com/en-us/sql/relational-d Database / system - stored-procedures / sp - fkeys - transact - sql


29

Penso che questo script sia meno costoso:

SELECT f.name AS ForeignKey, OBJECT_NAME(f.parent_object_id) AS TableName,
    COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
    OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
    COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id

6

Uno che mi piace davvero usare è chiamato SQL Dependency Tracker di Red Gate Software . È possibile inserire qualsiasi oggetto di database come tabelle, stored procedure, ecc. E quindi traccerà automaticamente le linee di relazione tra tutti gli altri oggetti che si basano sugli articoli selezionati.

Fornisce un'ottima rappresentazione grafica delle dipendenze nel tuo schema.


2
È anche un ottimo strumento per mostrare alle persone non tecniche che devono spendere un po 'di soldi per rifattorizzare la progettazione del loro database prima che tutto cada. I grafici che genera sono abbastanza convincenti.
Rob Allen,

1
Rob: Mi piace caricare un intero schema di database e poi cambiare tra i diversi layout in modo da poter vedere tutto volare.
TheTXI

4

Grazie mille a John Sansom, la sua domanda è formidabile!

Inoltre: è necessario aggiungere "AND PT.ORDINAL_POSITION = CU.ORDINAL_POSITION" alla fine della query.

Se hai più campi nella chiave primaria, questa affermazione abbinerà i campi corrispondenti tra loro (ho avuto il caso, la tua query ha creato tutte le combinazioni, quindi per 2 campi nella chiave primaria, ho avuto 4 risultati per la chiave esterna corrispondente) .

(Mi dispiace non posso commentare la risposta di John perché non ho abbastanza punti reputazione).


3

Questa query restituirà i dettagli sulle chiavi esterne in una tabella, supporta più chiavi di colonna.

    SELECT *
    FROM
    (
    SELECT 
    T1.constraint_name ConstraintName,
    T2.COLUMN_NAME ColumnName,
    T3.TABLE_NAME RefTableName, 
    T3.COLUMN_NAME RefColumnName,
    T1.MATCH_OPTION MatchOption, 
    T1.UPDATE_RULE UpdateRule, 
    T1.DELETE_RULE DeleteRule
    FROM 
    INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS T1
    INNER JOIN
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE T2 
    ON T1.CONSTRAINT_NAME = T2.CONSTRAINT_NAME
    INNER JOIN
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE T3 
    ON T1.UNIQUE_CONSTRAINT_NAME = T3.CONSTRAINT_NAME 
    AND T2.ORDINAL_POSITION = T3.ORDINAL_POSITION) A
    WHERE A.ConstraintName = 'table_name'

2

Dopo lunghe ricerche ho trovato una soluzione funzionante. Il mio database non usa sys.foreign_key_columns e information_schema.key_column_usage contiene solo chiavi primarie.

Uso SQL Server 2015

SOLUZIONE 1 (usato raramente)

Se altre soluzioni non funzionano, funzionerà bene:

        WITH CTE AS
        (
            SELECT 
                TAB.schema_id,
                TAB.name,
                COL.name AS COLNAME,
                COl.is_identity
            FROM 
                sys.tables TAB INNER JOIN sys.columns COL 
                    ON TAB.object_id = COL.object_id
        )
        SELECT 
            DB_NAME() AS [Database], 
            SCHEMA_NAME(Child.schema_id) AS 'Schema',
            Child.name AS 'ChildTable',
            Child.COLNAME AS 'ChildColumn',
            Parent.name AS 'ParentTable',
            Parent.COLNAME AS 'ParentColumn'
        FROM 
            cte Child INNER JOIN CTE Parent
                ON 
                    Child.COLNAME=Parent.COLNAME AND 
                    Child.name<>Parent.name AND 
                    Child.is_identity+1=Parent.is_identity

SOLUZIONE 2 (comunemente usata)

Nella maggior parte dei casi questo funzionerà perfettamente:

        SELECT
            DB_NAME() AS [Database], 
            SCHEMA_NAME(fk.schema_id) AS 'Schema',
            fk.name 'Name',
            tp.name 'ParentTable',
            cp.name 'ParentColumn',
            cp.column_id,
            tr.name 'ChildTable',
            cr.name 'ChildColumn',
            cr.column_id
        FROM
            sys.foreign_keys fk
        INNER JOIN
            sys.tables tp ON fk.parent_object_id = tp.object_id
        INNER JOIN
            sys.tables tr ON fk.referenced_object_id = tr.object_id
        INNER JOIN
            sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
        INNER JOIN
            sys.columns cp ON fkc.parent_column_id = cp.column_id AND fkc.parent_object_id = cp.object_id
        INNER JOIN
            sys.columns cr ON fkc.referenced_column_id = cr.column_id AND fkc.referenced_object_id = cr.object_id
        WHERE 
            -- CONCAT(SCHEMA_NAME(fk.schema_id), '.', tp.name, '.', cp.name) LIKE '%my_table_name%' OR
            -- CONCAT(SCHEMA_NAME(fk.schema_id), '.', tr.name, '.', cr.name) LIKE '%my_table_name%' 
        ORDER BY
            tp.name, cp.column_id

2

È possibile utilizzare INFORMATION_SCHEMA.KEY_COLUMN_USAGE e sys.foreign_key_columns per ottenere i metadati della chiave esterna per una tabella, ad esempio nome del vincolo, tabella di riferimento e colonna di riferimento, ecc.

Di seguito è la query:

SELECT  CONSTRAINT_NAME, COLUMN_NAME, ParentTableName, RefTableName,RefColName FROM 
    (SELECT CONSTRAINT_NAME,COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = '<tableName>') constraint_details
    INNER JOIN  
    (SELECT ParentTableName, RefTableName,name ,COL_NAME(fc.referenced_object_id,fc.referenced_column_id) RefColName  FROM (SELECT object_name(parent_object_id) ParentTableName,object_name(referenced_object_id) RefTableName,name,OBJECT_ID  FROM sys.foreign_keys WHERE parent_object_id = object_id('<tableName>') ) f 
    INNER JOIN   
    sys.foreign_key_columns AS fc  ON  f.OBJECT_ID = fc.constraint_object_id ) foreign_key_detail 
    on foreign_key_detail.name = constraint_details.CONSTRAINT_NAME

1

Solo una nota per la risposta di "John Sansom",

Se si cercano le dipendenze delle chiavi esterne , penso che la clausola PT Where dovrebbe essere:

i1.CONSTRAINT_TYPE = 'FOREIGN KEY'  -- instead of 'PRIMARY KEY'

ed è la condizione ON :

ON PT.TABLE_NAME = FK.TABLE_NAME  instead of PK.TABLE_NAME

Come comunemente viene utilizzata la chiave primaria della tabella esterna, penso che questo problema non sia stato notato prima.


0
SELECT  obj.name AS FK_NAME,
    sch.name AS [schema_name],
    tab1.name AS [table],
    col1.name AS [column],
    tab2.name AS [referenced_table],
    col2.name AS [referenced_column]
FROM sys.foreign_key_columns fkc
INNER JOIN sys.objects obj
    ON obj.object_id = fkc.constraint_object_id
INNER JOIN sys.tables tab1
    ON tab1.object_id = fkc.parent_object_id
INNER JOIN sys.schemas sch
    ON tab1.schema_id = sch.schema_id
INNER JOIN sys.columns col1
    ON col1.column_id = parent_column_id AND col1.object_id = tab1.object_id
INNER JOIN sys.tables tab2
    ON tab2.object_id = fkc.referenced_object_id
INNER JOIN sys.columns col2
    ON col2.column_id = referenced_column_id AND col2.object_id = tab2.object_id

Ti darà:

Lo stesso FK Schema a cui appartiene l'FK

  • La "tabella di riferimento" o la tabella che ha l'FK
  • La "colonna di riferimento" o la colonna all'interno della tabella di riferimento che punta all'FK
  • La "tabella di riferimento" o la tabella con la colonna chiave a cui punta l'FK
  • La "colonna di riferimento" o la colonna che è la chiave a cui punta il tuo FK

-1

USE information_schema;

SELECT COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
FROM KEY_COLUMN_USAGE
WHERE (table_name = *tablename*) AND NOT (REFERENCED_TABLE_NAME IS NULL)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.