10

I'm looking for a query allowing to retrieve foreign key infos (each line: referrencing table & field, referrenced table & field) of an entire schema.

I've found this, but does not gives all the info I need: https://stackoverflow.com/questions/4389228/sql-for-oracle-to-check-if-a-constraint-exists

I'm currently working on it and may end up with a solution in the next minutes/hours. But if someone has already a full working solution, I'll be glad to know it :)

asked Jan 20, 2012 at 15:14
1
  • For SQL Developer, you can find this info in an ERD format in the 'Model' tab on a table (as referenced here. Not useful for a script, but if you just need the info and land here like I did, it may be helpful. Commented Mar 21, 2017 at 15:02

4 Answers 4

16

After some "reverse-engineering" on the queries made by the Navicat tool when opening the design table window for a table (queries retrieving info about foreign keys show up in the history window), here is a solution:

SELECT
 CONS.CONSTRAINT_NAME,
 CONS.TABLE_NAME,
 COLS.COLUMN_NAME,
 CONS.R_CONSTRAINT_NAME,
 CONS_R.TABLE_NAME R_TABLE_NAME,
 COLS_R.COLUMN_NAME R_COLUMN_NAME
FROM USER_CONSTRAINTS CONS
 LEFT JOIN USER_CONS_COLUMNS COLS ON COLS.CONSTRAINT_NAME = CONS.CONSTRAINT_NAME
 LEFT JOIN USER_CONSTRAINTS CONS_R ON CONS_R.CONSTRAINT_NAME = CONS.R_CONSTRAINT_NAME
 LEFT JOIN USER_CONS_COLUMNS COLS_R ON COLS_R.CONSTRAINT_NAME = CONS.R_CONSTRAINT_NAME
-- returns only foreign key constraints
WHERE CONS.CONSTRAINT_TYPE = 'R'
ORDER BY CONS.TABLE_NAME, COLS.COLUMN_NAME
answered Jan 20, 2012 at 15:31
3

SQL Developer ships with a report that does just this.

It does it for the login schema only, but it's a quick fix to make it go get every single FK in the database - although you might want to omit schemas like 'APEX...' and 'SYS.'

It also omits things like, tables in the recycle bin.

The original report is in the Reports panel, in the data dictionary reports.

Here's the amended query to get ALL the FKs.

 SELECT
 c.owner "Owner",
 c.table_name "Table_Name",
 c.constraint_name "Constraint_Name",
 c.delete_rule "Delete_Rule",
 d.columns,
 c.r_owner "Owner of Related Table",
 (
 SELECT
 r.table_name
 FROM
 sys.all_constraints r
 WHERE
 c.r_owner = r.owner
 AND
 c.r_constraint_name = r.constraint_name
 ) "Related Table",
 c.r_constraint_name "Related Constraint"
FROM
 sys.all_constraints c,
 (
 SELECT
 a.owner,
 a.table_name,
 a.constraint_name,
 MAX(
 DECODE(position,1,substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,2,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,3,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,4,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,5,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,6,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,7,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,8,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,9,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,10,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,11,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,12,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,13,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,14,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,15,','
 || substr(column_name,1,30),NULL)
 )
 || MAX(
 DECODE(position,16,','
 || substr(column_name,1,30),NULL)
 ) columns
 FROM
 sys.all_constraints a,
 sys.all_cons_columns b
 WHERE
 a.constraint_name = b.constraint_name
 AND
 a.owner = b.owner
 AND
 a.constraint_type = 'R'
 AND
 substr(a.table_name,1,4) != 'BIN$'
 AND
 substr(a.table_name,1,3) != 'DR$'
 AND (
 :table_name IS NULL
 OR
 instr(upper(a.table_name),upper(:table_name) ) > 0
 ) GROUP BY
 a.owner,
 a.table_name,
 a.constraint_name
 ) d
WHERE
 c.owner = d.owner
AND
 c.table_name = d.table_name
AND
 c.constraint_name = d.constraint_name
ORDER BY
 c.owner,
 c.table_name,
 c.constraint_name

And here's what that report looks like.

enter image description here

answered Feb 2, 2017 at 18:25
0
2

A little bit complicated code which also dump comments on cols (based on Frosty code):

SELECT
 dt.table_name, dt.column_name, dt.data_type, dt.data_length,
 constr.r_tbl r_table, constr.r_col r_column,
 comm.comments
 FROM user_col_comments comm, user_tab_columns dt
 LEFT OUTER JOIN (
 SELECT
 cons.table_name tbl,
 cols.column_name col,
 cons_r.table_name r_tbl,
 cols_r.column_name r_col
 FROM user_constraints cons
 LEFT JOIN user_cons_columns cols ON cols.constraint_name = cons.constraint_name
 LEFT JOIN user_constraints cons_r ON cons_r.constraint_name = cons.r_constraint_name
 LEFT JOIN user_cons_columns cols_r ON cols_r.constraint_name = cons.r_constraint_name
 WHERE cons.constraint_type = 'R'
 ) constr ON constr.tbl = dt.table_name AND constr.col = dt.column_name
 WHERE dt.table_name = comm.table_name
 AND dt.column_name = comm.column_name
 ORDER BY dt.table_name, dt.column_name
 ;

To make output more readable I use break on TABLE_NAME; in sqlplus (look to my question https://stackoverflow.com/questions/14998296/print-only-first-unique-value-for-column-that-order-by-in-oracle-sqlplus/ ).

UPDATE Simpler query that collects list of tables that have FK reference to given table (useful if you like to clean up constraints after table renames):

select * from SYS.USER_CONSTRAINTS cons
 join SYS.USER_CONSTRAINTS rcons on rcons.CONSTRAINT_NAME = cons.R_CONSTRAINT_NAME
 where cons.CONSTRAINT_TYPE = 'R' and rcons.TABLE_NAME 'TBL_NAME';
select * from SYS.USER_CONSTRAINTS cons
 join SYS.USER_CONSTRAINTS rcons on rcons.CONSTRAINT_NAME = cons.R_CONSTRAINT_NAME
 where cons.CONSTRAINT_TYPE = 'R' and rcons.TABLE_NAME like '%/_OLD' escape '/';
answered Feb 21, 2013 at 14:00
2

Found out that most of these scripts have issues when foreign key constraint references a table with more than one column reference.

Here is the one I use:

 SELECT c.constraint_name,
 l.table_name,
 l.column_name,
 r.table_name,
 r.column_name
 FROM user_constraints c,
 user_cons_columns l,
 user_cons_columns r
 WHERE l.table_name = c.table_name
 -- AND c.table_name = :tname
 AND c.r_constraint_name = r.constraint_name
 AND c.constraint_name = l.constraint_name
 AND l.position = r.position
answered Sep 28, 2021 at 12:04

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.