2010-10-11 9 views
28

In SQL Server, come posso ottenere il nome della tabella e della colonna referenziate da una chiave esterna?SQL Server: come ottenere il riferimento di chiave esterna da information_schema?

Nota: non la tabella/colonna in cui si trova la chiave, ma la chiave a cui fa riferimento.

Esempio:

Quando la chiave [FA_MDT_ID] nella tabella [T_ALV_Ref_FilterDisplay]. si riferisce a [T_AP_Ref_Customer].[MDT_ID]

come ad esempio quando si crea un vincolo del genere:

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 

ho bisogno di ottenere [T_AP_Ref_Customer].[MDT_ID] quando somministrato [T_ALV_Ref_FilterAnzeige].[FA_MDT_ID] come input

risposta

63

Non importa, questa è la risposta corretta:
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

Attenzione! - Questo non restituisce fks che fanno riferimento a colonne indice univoche. Vedi http://stackoverflow.com/questions/2895219/can-we-have-a-foreign-key-which-is-not-a-primary-key-in-any-other-table. –

+2

@Seth Reno: questo è corretto in Microsoft SQL Server, poiché è possibile fare riferimento a un indice univoco in una chiave esterna. Ma lo standard SQL non lo consente e questo non è supportato da tutti gli altri DBMS. Inoltre, non ci sono informazioni sull'indice disponibili in information_schema, quindi non c'è modo di correggerlo. Direi che se non si fa riferimento a una chiave primaria come chiave esterna, si sta facendo qualcosa di sbagliato in termini di schema. –

+0

Questa query funziona quasi correttamente per me. Ho dovuto aggiungere 'AND KCU2.TABLE_NAME = RC.REFERENCED_TABLE_NAME' alla clausola ON di KCU2 JOIN per eliminare i record errati a causa di molte tabelle nel mio database con una chiave primaria chiamata' PRIMARY'. Mi capita di eseguire MariaDB 5.5, ma sospetto che altri DBMS avranno un problema simile. – JSmitty

13

Se si può vivere con utilizzando lo schema specifico di SQL Server visualizzazioni del catalogo, questa query restituirà quello che stai cercando:

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 

Non so come - se non del tutto - è possibile ottenere le stesse informazioni da visualizzazioni INFORMATION ....

+0

37'874 chiavi esterne nel mio database con circa 100 tavoli? Non ne sono sicuro, ma non penso sia corretto. Ottengo 349, che penso sia più probabile ... –

+2

@Quandary: scusate, mancate alcune condizioni ON - questo dovrebbe essere migliore ora (funziona per me, comunque) –

+0

Come join interno con INFORMATION_SCHEMA.KEY_COLUMN_USAGE per ottenere ORDINAL_POSITION del campo? –

0

volevo aa versione che mi permettesse di trovare tutte le colonne "Chiave" e "ID" con/senza un vincolo. Quindi volevo tutte le colonne rispetto alla lista di tutti i PK O FK O Null, ecco la mia richiesta. Spero che aiuti qualcun altro!

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 
; 

formattazione per gentile concessione di: http://www.dpriver.com/pp/sqlformat.htm

+0

Si prega di prendere il tempo per passare alle opzioni appropriate quando si utilizza sqlformat. La tua versione era completamente illeggibile. Risolto il problema. Inoltre, usa AS quando dichiari un alias. Ciò ti aiuterà a evitare molti potenziali problemi.SqlFormat formatterà per te, ma non pensa per te. –

+0

@StefanSteiger grazie per il feedback. Non ho mai postato query lunghe su SO, quindi non ero sicuro delle migliori opzioni da utilizzare. lo terrò a mente per la prossima volta. Cercherò anche di ricordare di includere il qualificatore "AS", questa è una cattiva abitudine che sto lavorando costantemente per migliorare! – Justin