Comment trouver les dépendances de clé étrangère dans SQL Server?

163

Comment puis-je trouver toutes les dépendances de clé étrangère sur une colonne particulière?

Quelles sont les différentes alternatives (graphiquement dans SSMS, requêtes / vues dans SQL Server, outils de base de données tiers, code dans .NET)?

Même Mien
la source

Réponses:

290

La requête suivante vous aidera à démarrer. Il répertorie toutes les relations de clé étrangère dans la base de données actuelle.

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

Vous pouvez également afficher graphiquement les relations dans SQL Server Management Studio dans les diagrammes de base de données.

John Sansom
la source
8
Merci! J'avais juste besoin d'ajouter << WHERE FK.TABLE_NAME = 'MyTable' AND CU.COLUMN_NAME = 'MyColumn' >> pour obtenir la colonne spécifique.
Even Mien
1
+1! Et si nécessaire pour obtenir la colonne spécifique mais pour toutes les tables, "WHERE CU.COLUMN_NAME = 'MyColumn'" ferait l'affaire.
liang
1
Similaire à Even - J'ai utilisé WHERE PK.TABLE_NAME = 'MyTable' pour trouver la table dont dépendait.
Lanceomagnifico
7
@samkitshah: Personne ne l'a dit. La question est étiquetée sql-server, qui par définition est la technologie Microsoft. Postgres n'a rien à voir avec cela.
Neolisk
2
-1: cette requête manque les clés étrangères qui sont sauvegardées par une contrainte unique ou un index unique, plutôt que par une clé primaire, dans la table référencée. Par MSDN : «Une contrainte de clé étrangère ne doit pas être liée uniquement à une contrainte de clé primaire dans une autre table; il peut également être défini pour référencer les colonnes d'une contrainte UNIQUE dans une autre table. » La réponse peut être faite pour fonctionner avec des contraintes uniques en supprimant la dernière jointure et avec des index uniques en supprimant les deux dernières jointures, mais cela restreint les informations renvoyées.
Douglas
100

essayer: sp_help [table_name]

vous obtiendrez toutes les informations sur la table, y compris toutes les clés étrangères

Andrija
la source
2
belle, très utile. Plus mémorable que la réponse marquée! Je ne peux pas croire que vous ne pouvez pas simplement les voir dans ssms!
JonnyRaa
4
Très gentil merci. Mais pour chercher des FK, je préfère la sortie de la réponse de Michael ci-dessous: sp_fkeys [table]
AjV Jsy
.... ou si vous n'obtenez aucun résultat (mais sp_help affiche les clés étrangères), la version plus complète peut vous aider:sp_fkeys @fktable_name='TableName'
AjV Jsy
superbe! bref et concis!
zeroflaw
39

Si vous prévoyez de supprimer ou de renommer une table ou une colonne, la recherche uniquement des dépendances de clé étrangère peut ne pas suffire.

Référencer des tables non connectées avec une clé étrangère - Vous devrez également rechercher des tables de référence qui pourraient ne pas être connectées avec une clé étrangère (j'ai vu de nombreuses bases de données avec une mauvaise conception qui n'avaient pas de clés étrangères définies mais qui avaient des données liées ). La solution peut être de rechercher le nom de la colonne dans toutes les tables et de rechercher des colonnes similaires.

Autres objets de base de données - c'est probablement un peu hors sujet, mais si vous cherchiez toutes les références, il est également important de vérifier les objets dépendants.

Outils GUI - Essayez l'option SSMS «Rechercher des objets associés» ou des outils tels que ApexSQL Search (outil gratuit, s'intègre dans SSMS) pour identifier tous les objets dépendants, y compris les tables connectées avec une clé étrangère.

Timothy Walden
la source
39

Puisque votre question est orientée vers une seule table, vous pouvez utiliser ceci:

EXEC sp_fkeys 'TableName'

Je l'ai trouvé sur SO ici:

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

J'ai trouvé les informations dont j'avais besoin assez rapidement. Il répertorie la table, la colonne et le nom de la clé étrangère.

ÉDITER

Voici un lien vers la documentation qui détaille les différents paramètres pouvant être utilisés: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-fkeys-transact-sql

Michael
la source
29

Je pense que ce script est moins cher:

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
RobSiklos
la source
6

Celui que j'aime vraiment utiliser s'appelle SQL Dependency Tracker de Red Gate Software . Vous pouvez mettre dans n'importe quel objet de base de données tels que des tables, des procédures stockées, etc. et il dessinera alors automatiquement les lignes de relation entre tous les autres objets qui reposent sur les éléments sélectionnés.

Donne une très bonne représentation graphique des dépendances dans votre schéma.

TheTXI
la source
2
C'est également un excellent outil pour montrer aux non-techniciens qu'ils doivent dépenser de l'argent pour refactoriser la conception de leur base de données avant que tout ne tombe en panne. Les graphiques qu'il génère sont assez convaincants.
Rob Allen
1
Rob: J'aime charger un schéma de base de données entier là-dedans, puis changer entre les différentes mises en page juste pour que je puisse regarder tout voler.
TheTXI
4

Merci beaucoup à John Sansom, sa requête est formidable!

De plus: vous devez ajouter "AND PT.ORDINAL_POSITION = CU.ORDINAL_POSITION" à la fin de votre requête.

Si vous avez plusieurs champs dans la clé primaire, cette instruction fera correspondre les champs correspondants les uns aux autres (j'ai eu le cas, votre requête a créé toutes les combinaisons, donc pour 2 champs dans la clé primaire, j'ai eu 4 résultats pour la clé étrangère correspondante) .

(Désolé, je ne peux pas commenter la réponse de John car je n'ai pas assez de points de réputation).

Sierramike
la source
3

Cette requête renverra des détails sur les clés étrangères dans une table, elle prend en charge plusieurs clés de colonne.

    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'
Kumait
la source
3

Après de longues recherches, j'ai trouvé une solution de travail. Ma base de données n'utilise pas les sys.foreign_key_columns et les informations_schema.key_column_usage ne contiennent que des clés primaires.

J'utilise SQL Server 2015

SOLUTION 1 (rarement utilisée)

Si les autres solutions ne fonctionnent pas, cela fonctionnera correctement:

        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

SOLUTION 2 (couramment utilisée)

Dans la plupart des cas, cela fonctionnera très bien:

        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
profimedica
la source
2

Vous pouvez utiliser INFORMATION_SCHEMA.KEY_COLUMN_USAGE et sys.foreign_key_columns afin d'obtenir les métadonnées de clé étrangère pour une table, à savoir le nom de la contrainte, la table de référence et la colonne de référence, etc.

Voici la requête:

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
Shreyansh Bothra
la source
1

Juste une note pour la réponse @ "John Sansom",

Si les dépendances de clé étrangère sont recherchées, je pense que la clause PT Where devrait être:

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

et c'est la condition ON :

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

Comme la clé primaire de la table étrangère est couramment utilisée, je pense que ce problème n'a pas été remarqué auparavant.

Homo Programmatoris
la source
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

Cela vous donnera:

Le FK lui-même Schéma auquel appartient le FK

  • La "table de référencement" ou la table qui a le FK
  • La "colonne de référence" ou la colonne à l'intérieur de la table de référence qui pointe vers le FK
  • La "table référencée" ou la table contenant la colonne clé vers laquelle pointe votre FK
  • La "colonne référencée" ou la colonne qui est la clé vers laquelle pointe votre FK
Divya Agrawal
la source
-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)
Dave
la source