2010-10-11 19 views
28

Dans SQL Server, comment puis-je obtenir le nom de table + colonne référencé à partir d'une clé étrangère?SQL Server: Comment obtenir une référence de clé étrangère à partir de information_schema?

Remarque: Ce n'est pas la table/colonne où se trouve la clé, mais la clé à laquelle elle fait référence.

Exemple:

Lorsque la [FA_MDT_ID] clé dans le tableau [T_ALV_Ref_FilterDisplay]. fait référence à [T_AP_Ref_Customer].[MDT_ID]

, comme lors de la création d'une contrainte comme ceci:

ALTER TABLE [dbo].[T_ALV_Ref_FilterDisplay] WITH CHECK ADD CONSTRAINT [FK_T_ALV_Ref_FilterDisplay_T_AP_Ref_Customer] FOREIGN KEY([FA_MDT_ID]) 
REFERENCES [dbo].[T_AP_Ref_Customer] ([MDT_ID]) 
GO 

Je dois obtenir [T_AP_Ref_Customer].[MDT_ID] lorsqu'il est administré [T_ALV_Ref_FilterAnzeige].[FA_MDT_ID] comme entrée

Répondre

63

Peu importe, c'est la bonne réponse:
http://msdn.microsoft.com/en-us/library/aa175805(SQL.80).aspx

SELECT 
    KCU1.CONSTRAINT_NAME AS FK_CONSTRAINT_NAME 
    ,KCU1.TABLE_NAME AS FK_TABLE_NAME 
    ,KCU1.COLUMN_NAME AS FK_COLUMN_NAME 
    ,KCU1.ORDINAL_POSITION AS FK_ORDINAL_POSITION 
    ,KCU2.CONSTRAINT_NAME AS REFERENCED_CONSTRAINT_NAME 
    ,KCU2.TABLE_NAME AS REFERENCED_TABLE_NAME 
    ,KCU2.COLUMN_NAME AS REFERENCED_COLUMN_NAME 
    ,KCU2.ORDINAL_POSITION AS REFERENCED_ORDINAL_POSITION 
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1 
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG 
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU2 
    ON KCU2.CONSTRAINT_CATALOG = RC.UNIQUE_CONSTRAINT_CATALOG 
    AND KCU2.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA 
    AND KCU2.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME 
    AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION 
+3

Attention! - Cela ne retourne pas les fks qui référencent des colonnes d'index uniques. Voir http://stackoverflow.com/questions/2895219/can-we-have-a-key-fore-which-is-not-a-primary-key-in-other-other-table. –

+2

@Seth Reno: Ceci est correct dans Microsoft SQL Server, car là vous pouvez référencer un index unique dans une clé étrangère. Mais le standard SQL ne le permet pas, et ceci n'est pas supporté par tous les autres SGBD. De plus, il n'y a pas d'information d'index disponible dans information_schema, donc il n'y a aucun moyen de corriger cela. Je dirais que si vous ne faites pas référence à une clé primaire en tant que clé étrangère, vous faites quelque chose de mal en termes de schémas. –

+0

Cette requête fonctionne presque correctement pour moi. J'ai dû ajouter 'AND KCU2.TABLE_NAME = RC.REFERENCED_TABLE_NAME' à la clause ON du KCU2 JOIN afin d'éliminer les enregistrements incorrects en raison de nombreuses tables dans ma base de données avec une clé primaire nommée' PRIMARY'. Il se trouve que je cours avec MariaDB 5.5, mais je soupçonne que d'autres SGBD auront un problème similaire. – JSmitty

13

Si vous pouvez vivre avec l'aide du schéma spécifique de SQL Server vues de catalogue, cette requête retournera ce que vous cherchez:

SELECT 
    fk.name, 
    OBJECT_NAME(fk.parent_object_id) 'Parent table', 
    c1.name 'Parent column', 
    OBJECT_NAME(fk.referenced_object_id) 'Referenced table', 
    c2.name 'Referenced column' 
FROM 
    sys.foreign_keys fk 
INNER JOIN 
    sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id 
INNER JOIN 
    sys.columns c1 ON fkc.parent_column_id = c1.column_id AND fkc.parent_object_id = c1.object_id 
INNER JOIN 
    sys.columns c2 ON fkc.referenced_column_id = c2.column_id AND fkc.referenced_object_id = c2.object_id 

Je ne sais pas comment - si tout - vous pouvez obtenir les mêmes informations à partir des vues INFORMATION_SCHEMA ....

+0

37'874 dans ma base de données avec environ 100 tables? Je ne suis pas sûr, mais je ne pense pas que ce soit correct. Je reçois 349, ce qui je pense est plus probable ... –

+2

@Quandary: désolé, manqué quelques conditions ON - cela devrait être mieux maintenant (travaille pour moi, de toute façon) –

+0

Comment interne rejoindre cela avec INFORMATION_SCHEMA.KEY_COLUMN_USAGE pour obtenir le ORDINAL_POSITION du champ? –

0

Je voulais aa version qui me permettrait de trouver toutes les colonnes "Key" et "ID" ayant/manquant une contrainte. Donc, je voulais toutes les colonnes par rapport à la liste de tous PK OU FK OU Null, voici ma requête. J'espère que ça aide quelqu'un d'autre!

SELECT 
    c.table_schema 
    ,c.table_name 
    ,c.column_name 
    ,KeyConstraints.constraint_type 
    ,KeyConstraints.constraint_schema 
    ,KeyConstraints.constraint_name 
    ,KeyConstraints.referenced_table_schema 
    ,KeyConstraints.referenced_table_name 
    ,KeyConstraints.referenced_column_name 
    ,KeyConstraints.update_rule 
    ,KeyConstraints.delete_rule 
FROM information_schema.columns AS c 
LEFT JOIN 
    (
     SELECT 
      FK.table_schema AS TABLE_SCHEMA 
      ,FK.table_name 
      ,CU.column_name 
      ,FK.constraint_type 
      ,c.constraint_schema 
      ,C.constraint_name 
      ,PK.table_schema AS REFERENCED_TABLE_SCHEMA 
      ,PK.table_name AS REFERENCED_TABLE_NAME 
      ,CCU.column_name AS REFERENCED_COLUMN_NAME 
      ,C.update_rule 
      ,C.delete_rule 
     FROM information_schema.referential_constraints AS C 

     INNER JOIN information_schema.table_constraints AS FK 
      ON C.constraint_name = FK.constraint_name 

     INNER JOIN information_schema.table_constraints AS PK 
      ON C.unique_constraint_name = PK.constraint_name 

     INNER JOIN information_schema.key_column_usage AS CU 
      ON C.constraint_name = CU.constraint_name 

     INNER JOIN information_schema.constraint_column_usage AS CCU 
      ON PK.constraint_name = CCU.constraint_name 

     WHERE (FK.constraint_type = 'FOREIGN KEY') 

     UNION 

     SELECT 
      ccu.table_schema 
      ,ccu.table_name 
      ,ccu.column_name 
      ,tc.constraint_type 
      ,ccu.constraint_schema 
      ,ccu.constraint_name 
      ,NULL 
      ,NULL 
      ,NULL 
      ,NULL 
      ,NULL 
     FROM information_schema.constraint_column_usage ccu 

     INNER JOIN information_schema.table_constraints tc 
      ON ccu.table_schema = tc.table_schema 
      AND ccu.table_name = tc.table_name 

     WHERE tc.constraint_type = 'PRIMARY KEY' 

    ) AS KeyConstraints 
    ON c.table_schema = KeyConstraints.table_schema 
    AND c.table_name = KeyConstraints.table_name 
    AND c.column_name = KeyConstraints.column_name 

WHERE c.column_name LIKE '%ID' OR c.column_name LIKE '%Key' 
ORDER BY c.table_schema 
     ,c.table_name 
     ,c.column_name 
; 

mise en forme avec la permission de: http://www.dpriver.com/pp/sqlformat.htm clés étrangères

+0

Veuillez prendre le temps de passer aux bonnes options lors de l'utilisation de sqlformat. Votre version était totalement illisible. Corrigé cela. En outre, utilisez AS lors de la déclaration d'un alias. Cela vous aidera à éviter beaucoup de problèmes potentiels.SqlFormat formatera pour vous, mais il ne pense pas pour vous. –

+0

@StefanSteiger merci pour les commentaires. Je n'ai pas posté de longues requêtes sur SO souvent donc je n'étais pas sûr des meilleures options à utiliser. Je garderai cela à l'esprit pour la prochaine fois. Je vais aussi essayer de me souvenir d'inclure le qualificatif "AS", c'est une mauvaise habitude que je travaille constamment à améliorer! – Justin