Displaying foreign key relationships in Oracle 9i - oracle

Is there a command in oracle 9i that displays the foreign keys of a table and also the table that those foreign keys reference?
I was searching, did not find anything but i found an equivalent command that works with MySql which is SHOW CREATE TABLE
Is there an equivalent command for this within oracle's SQL?
I appreciate your response, however I thought there was a really short way of doing this like MySql.

Here's another answer: The dbms_metadata package has a function that can return the DDL for a table definition.
SELECT dbms_metadata.get_ddl('TABLE', '<table>', '<schema>') FROM dual;
This package has apparently been available since Oracle 9.2
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96612/d_metada.htm#1656

You could start by listing all of the constraints for the table along with any referenced constraint on other tables:
SELECT
acc.table_name
,acc.column_name
,acc.constraint_name
,ac.r_constraint_name AS referenced_constraint
FROM all_cons_columns acc
INNER JOIN all_constraints ac ON (acc.constraint_name = ac.constraint_name)
WHERE acc.table_name = UPPER('your_table_here');
If you have sensible naming conventions for your constraints it should be possible to identify which are the foreign keys, an 'FK' prefix/suffix is typical.

This may do what you want, it uses Oracle system views. I don't have an Oracle instance handy to test it, however.
SELECT fk.owner, fk.constraint_name, fk.table_name, fc.column_name,
pk.owner, pk.constraint_name, pk.table_name, pc.column_name
FROM all_constraints fk
JOIN all_cons_columns fc ON (fk.owner = fc.owner AND fk.constraint_name = fc.constraint_name)
JOIN (all_constraints pk
JOIN all_cons_columns pc ON (pk.owner = pc.owner AND pk.constraint_name = pc.constraint_name))
ON (fk.r_owner = pk.owner AND fk.r_constraint_name = pk.constraint_name
AND fc.position = pc.position)
WHERE fk.constraint_type = 'R' AND pk.constraint_type IN ('P', 'U')
AND fk.owner = '<schema>' AND fk.table_name = '<table>';

If you need the DDL for the foreign keys in the future, then here is the answer in advance :)
select
DBMS_METADATA.GET_DEPENDENT_DDL('REF_CONSTRAINT' ,atb.table_name, atb.owner)
from
all_tables atb, all_constraints ac
where
atb.owner = ac.owner and
ac.constraint_type = 'R' and
ac.table_name = atb.table_name and
atb.owner = 'YOURSCHEMA';

Related

Ordering columns by Primary Key position in PostgreSQL

I am new to PostgreSQL and was wondering if there is a table which matches Oracle's user_cons_columns table which provides a column position column similar to user_cons_columns.position. Essentially, I am trying to convert the following oracle code to PostgreSQL. It attains the PK columns in order of PK definition:
Oracle Code (Original):
select a.table_name tab_name,
a.colum_name col_name,
a.position col_order
from user_cons_columns a,
user_constraints b
where a.table_name = b.table_name
and a.constraint_name = b.constraint_name
and b.constraint_type = 'P'
and a.table_name = 'some_table_name';
PostgreSQL Code (Oracle Equiv):
/* Below is my attempt at the PostgreSQL conversion */
select isc.table_name tab_name,
isc.column_name col_name,
isc.ordinal_position col_order
from pg_attribute as pga
inner join pg_class as pgc on pga.attrelid = pgc.oid
inner join pg_namespace as pgn on pgn.oid = pgc.relnamespace
inner join information_schema.columns as isc on isc.column_name = pga.attname
and isc.table_name = pgc.relname
where isc.table_name = 'sometablename';
In my PostgreSQL conversion attempt I am missing the relationship between the constraint and its position but use the column position. Which is not the same. Is there a way to do the former? Thanks in advance!
The column numbers of a constraint and their order are stored in pg_constraint.conkey; for foreign keys, the corresponding numbers of the target columns are in pg_constraint.confkey.
The description of table columns is in pg_attribute; the column number is stored in attnum.
Below is the solution that I derived thanks to the answer from #Laurenz Albe.
select isc.table_name tab_name,
isc.col_name col_name,
pgco.conkey[1] col_order
from pg_attribute as pga
inner join pg_class as pgc on pga.attrelid = pgc.oid
inner join pg_namespace as pgn on pgn.oid = pgc.relnamespace
inner join information_schema.columns as isc on isc.column = pga.attname
and isc.table_name = pgc.relname
inner join pg_constraint as pgco on pgco.conkey[1] = pga.attnum
and pgco.connamespace = pgc.relnamespace
and pgco.conrelid = pga.attrelid
where isc.table_name = 'sometablename'
and pgco.contype ='p';
Hope this is useful to someone else.

Smart Oracle tool to find missing field relationships

Does Oracle have a tool I can use to analyze a database and help determine possible missing field relationships? We have a legacy database with 150+ tables and many relationships are missing. We could go through it by hand but an automated tool might be useful. So find things like missing foreign keys and whatnot.
I've had to do this a few times now. I find it's a very human-intelligence kind of thing - helped by running a lot of queries across both the data dictionary (e.g. EvilTeach's query), querying sample data from the columns, examining how the data is created by the application, and understanding the business requirements and user processes.
For example, in many legacy applications I find constraints (including referential integrity constraints) that are checked and implemented in the front-end application, which means the data follows the constraint (almost 100% :) ) but it's not actually constrained at the database level. Lots of fun results.
I'd be surprised if a tool could do any of this automatically and yield useful results.
This might be a good start
select column_name, table_name, data_type
from user_tab_cols
order by column_name, table_name
You could find a POSSIBLE foreign key absence if you assume that you could identify a POSSIBLE foreign key relationshinp by finding columns with equal names and data types in different tables, one of which is a primary key, and another one has no reference to that key.
You could use a query like this:
select c1.TABLE_NAME, c1.COLUMN_NAME, c2.TABLE_NAME, c2.COLUMN_NAME
from user_tab_columns c1,
user_tables at1,
user_tab_columns c2,
user_tables at2
where c1.COLUMN_NAME = c2.COLUMN_NAME
and c1.DATA_TYPE = c2.DATA_TYPE
and c1.TABLE_NAME = at1.TABLE_NAME
and c2.TABLE_NAME = at2.TABLE_NAME
and c1.TABLE_NAME != c2.TABLE_NAME
/*and c1.TABLE_NAME = 'TABLE' --check this for one table
and c1.COLUMN_NAME = 'TABLE_PK'*/
and not exists (select 1
from user_cons_columns ucc,
user_constraints uc,
user_constraints uc2,
user_cons_columns ucc2
where ucc.CONSTRAINT_NAME = uc.CONSTRAINT_NAME
and uc.TABLE_NAME = ucc.TABLE_NAME
and ucc.table_name = c1.TABLE_NAME
and ucc.column_name = c1.COLUMN_NAME
and uc.CONSTRAINT_TYPE = 'P'
and uc2.table_name = c2.TABLE_NAME
and ucc2.column_name = c2.COLUMN_NAME
and uc2.table_name = ucc2.table_name
and uc2.r_constraint_name = uc.constraint_name
and uc2.constraint_type = 'R')
This one (a sketch, optimized in no way, though) scans through all pairs of column name-type equality, and finds if one is a PK, and another one doesn't reference it.
But, and here I agree with Jeffrey, it's a very human-intelligence kind of thing, and no tool will do this for sure. In any case you'll have to do it by hand.

Find if a column in Oracle has a sequence

I am attempting to figure out if a column in Oracle is populated from a sequence. My impression of how Oracle handles sequencing is that the sequence and column are separate entities and one needs to either manually insert the next sequence value like:
insert into tbl1 values(someseq.nextval, 'test')
or put it into a table trigger. Meaning that it is non-trivial to tell if a column is populated from a sequence. Is that correct? Any ideas about how I might go about figuring out if a column is populated from a sequence?
You are correct; the sequence is separate from the table, and a single sequence can be used to populate any table, and the values in a column in some table may mostly come from a sequence (or set of sequences), except for the values manually generated.
In other words, there is no mandatory connection between a column and a sequence - and therefore no way to discover such a relationship from the schema.
Ultimately, the analysis will be of the source code of all applications that insert or update data in the table. Nothing else is guaranteed. You can reduce the scope of the search if there is a stored procedure that is the only way to make modifications to the table, or if there is a trigger that sets the value, or other such things. But the general solution is the 'non-solution' of 'analyze the source'.
If the sequence is used in a trigger, it is possible to find which tables it populates:
SQL> select t.table_name, d.referenced_name as sequence_name
2 from user_triggers t
3 join user_dependencies d
4 on d.name = t.trigger_name
5 where d.referenced_type = 'SEQUENCE'
6 and d.type = 'TRIGGER'
7 /
TABLE_NAME SEQUENCE_NAME
------------------------------ ------------------------------
EMP EMPNO_SEQ
SQL>
You can vary this query to find stored procedures, etc that make use of the sequence.
There are no direct metadata links between Oracle sequences and any use in the database. You could make an intelligent guess if a column's values are related to a sequence by querying the USER_SEQUENCES metadata and comparing the LAST_NUMBER column to the data for the column.
select t.table_name,
d.referenced_name as sequence_name,
d.REFERENCED_OWNER as "OWNER",
c.COLUMN_NAME
from user_trigger_cols t, user_dependencies d, user_tab_cols c
where d.name = t.trigger_name
and t.TABLE_NAME = c.TABLE_NAME
and t.COLUMN_NAME = c.COLUMN_NAME
and d.referenced_type = 'SEQUENCE'
and d.type = 'TRIGGER'
As Jonathan pointed out: there is no direct way to relate both objects. However, if you "keep a standard" for primary keys and sequences/triggers you could find out by finding the primary key and then associate the constraint to the table sequence.
I was in need of something similar since we are building a multi-db product and I tried to replicate some classes with properties found in a DataTable object from .Net which has AutoIncrement, IncrementSeed and IncrementStep which can only be found in the sequences.
So, as I said, if you, for your tables, use a PK and always have a sequence associated with a trigger for inserts on a table then this may come handy:
select tc.table_name,
case tc.nullable
when 'Y' then 1
else 0
end as is_nullable,
case ac.constraint_type
when 'P' then 1
else 0
end as is_identity,
ac.constraint_type,
seq.increment_by as auto_increment_seed,
seq.min_value as auto_increment_step,
com.comments as caption,
tc.column_name,
tc.data_type,
tc.data_default as default_value,
tc.data_length as max_length,
tc.column_id,
tc.data_precision as precision,
tc.data_scale as scale
from SYS.all_tab_columns tc
left outer join SYS.all_col_comments com
on (tc.column_name = com.column_name and tc.table_name = com.table_name)
LEFT OUTER JOIN SYS.ALL_CONS_COLUMNS CC
on (tc.table_name = cc.table_name and tc.column_name = cc.column_name and tc.owner = cc.owner)
LEFT OUTER JOIN SYS.ALL_CONSTRAINTS AC
ON (ac.constraint_name = cc.constraint_name and ac.owner = cc.owner)
LEFT outer join user_triggers trg
on (ac.table_name = trg.table_name and ac.owner = trg.table_owner)
LEFT outer join user_dependencies dep
on (trg.trigger_name = dep.name and dep.referenced_type='SEQUENCE' and dep.type='TRIGGER')
LEFT outer join user_sequences seq
on (seq.sequence_name = dep.referenced_name)
where tc.table_name = 'TABLE_NAME'
and tc.owner = 'SCHEMA_NAME'
AND AC.CONSTRAINT_TYPE = 'P'
union all
select tc.table_name,
case tc.nullable
when 'Y' then 1
else 0
end as is_nullable,
case ac.constraint_type
when 'P' then 1
else 0
end as is_identity,
ac.constraint_type,
seq.increment_by as auto_increment_seed,
seq.min_value as auto_increment_step,
com.comments as caption,
tc.column_name,
tc.data_type,
tc.data_default as default_value,
tc.data_length as max_length,
tc.column_id,
tc.data_precision as precision,
tc.data_scale as scale
from SYS.all_tab_columns tc
left outer join SYS.all_col_comments com
on (tc.column_name = com.column_name and tc.table_name = com.table_name)
LEFT OUTER JOIN SYS.ALL_CONS_COLUMNS CC
on (tc.table_name = cc.table_name and tc.column_name = cc.column_name and tc.owner = cc.owner)
LEFT OUTER JOIN SYS.ALL_CONSTRAINTS AC
ON (ac.constraint_name = cc.constraint_name and ac.owner = cc.owner)
LEFT outer join user_triggers trg
on (ac.table_name = trg.table_name and ac.owner = trg.table_owner)
LEFT outer join user_dependencies dep
on (trg.trigger_name = dep.name and dep.referenced_type='SEQUENCE' and dep.type='TRIGGER')
LEFT outer join user_sequences seq
on (seq.sequence_name = dep.referenced_name)
where tc.table_name = 'TABLE_NAME'
and tc.owner = 'SCHEMA_NAME'
AND AC.CONSTRAINT_TYPE is null;
That would give you the list of columns for a schema/table with:
Table name
If column is nullable
Constraint type (only for PK's)
Increment seed (from the sequence)
Increment step (from the sequence)
Column comments
Column name, of course :)
Data type
Default value, if any
Length of column
Index (column id)
Precision (for numbers)
Scale (for numbers)
I'm pretty sure that code can be optimized but it works for me, I use it to "load metadata" for tables and then represent that metadata as entities on my frontend.
Note that I'm filtering only primary keys and not retrieving compound key constraints since I don't care about those. If you do you'll have to modify the code to do so and make sure that you filter duplicates since you could get one column twice (one for the PK constraint, another for the compound key).

Oracle all foreign key references

I've inherited a schema so don't have complete knowledge/confidence in what is there.
I have a project table with a projectId. There are a whole bunch of other tables that reference this table by project id. What I want to do is run a query to establish:
Which tables have foreign key references to the project table on
the project id
Which tables have a column called project id (in
case foreign keys are not set up).
If it was SQL Server I know how to query the metadata but how do I do this in Oracle?
1)
select table_name
from all_constraints
where r_constraint_name = [your pk/uk constraint on PROJECTS(id)]
2)
select table_name
from all_tab_columns
where column_name = 'PROJECT_ID'
You may want to add an extra predicate containing the OWNER column.
Regards,
Rob.
Ok. Here a request that give you the referenced table and column :
SELECT
c_list.CONSTRAINT_NAME as NAME,
substr(c_src.COLUMN_NAME, 1, 20) as SRC_COLUMN,
c_dest.TABLE_NAME as DEST_TABLE,
substr(c_dest.COLUMN_NAME, 1, 20) as DEST_COLUMN
FROM ALL_CONSTRAINTS c_list, ALL_CONS_COLUMNS c_src, ALL_CONS_COLUMNS c_dest
WHERE c_list.CONSTRAINT_NAME = c_src.CONSTRAINT_NAME
AND c_list.OWNER = c_src.OWNER
AND c_list.R_CONSTRAINT_NAME = c_dest.CONSTRAINT_NAME
AND c_list.OWNER = c_dest.OWNER
AND c_list.CONSTRAINT_TYPE = 'R'
AND c_src.OWNER = '<your-schema-here>'
AND c_src.TABLE_NAME = '<your-table-here>'
GROUP BY c_list.CONSTRAINT_NAME, c_src.TABLE_NAME,
c_src.COLUMN_NAME, c_dest.TABLE_NAME, c_dest.COLUMN_NAME;
Which give you something like this:
NAME |SRC_COLUMN |DEST_TABLE | DEST_COLUMN
----------------------|----------------|----------------------|-----------
CFK_RUB_FOR |FOR_URN |T03_FORMAT |FOR_URN
CFK_RUB_RUB |RUB_RUB_URN |T01_RUBRIQUE |RUB_URN
CFK_RUB_SUP |SUP_URN |T01_SUPPORT |SUP_URN
CFK_RUB_PRD |PRD_URN |T05_PRODUIT |PRD_URN
You can forget the substr() function if the result is usable without. This is not my case.
1): SELECT * FROM USER_CONSTRAINTS WHERE CONSTRAINT_NAME='R' and R_CONSTRAINT_NAME='xxx'
where xxx is the name of the primary key constraint on the project table
2): SELECT * FROM USER_TAB_COLUMNS WHERE COLUMN_NAME='PROJECT_ID'
The r_constraint_name answers here didn't seem to work for me, not sure why as I'm new to Oracle myself, but this worked:
SELECT * FROM ALL_CONSTRAINTS WHERE CONSTRAINT_NAME = '<constraint>';
My problem was slightly different. I have a table and I wanted to programatically know which other tables/columns it references.
I started with Stan's response above but this didn't give me exactly what I needed, so I came up with this, which I post here in case anyone else has my problem:
WITH src as
(SELECT ac.table_name, ac.constraint_name, accs.column_name, accs.position, ac.r_constraint_name
FROM ALL_CONSTRAINTS ac, all_cons_columns accs
WHERE ac.owner = '<owner>'
AND ac.constraint_type = 'R'
AND ac.table_name = '<src_table>'
AND accs.owner = ac.owner
AND accs.table_name = ac.table_name
AND accs.constraint_name = ac.constraint_name
ORDER BY ac.table_name, ac.constraint_name, accs.position),
dst as
(SELECT ac.table_name, ac.constraint_name, accs.column_name, accs.position
FROM ALL_CONSTRAINTS ac, all_cons_columns accs
WHERE ac.owner = '<owner>'
AND accs.owner = ac.owner
AND accs.table_name = ac.table_name
AND accs.constraint_name = ac.constraint_name
ORDER BY ac.table_name, ac.constraint_name, accs.position)
SELECT src.table_name as src_table,
dst.table_name as dst_table,
src.constraint_name as src_constraint,
src.column_name as src_column,
dst.column_name as dst_column,
src.position as position
FROM src,dst
WHERE src.r_constraint_name = dst.constraint_name
AND src.position = dst.position
Use this query.
select b.TABLE_NAME,b.CONSTRAINT_NAME ,a.COLUMN_NAME
from all_constraints b, all_cons_columns a
where r_constraint_name = 'Constraint_Name' and a.CONSTRAINT_NAME=b.CONSTRAINT_NAME;

ADO.NET OracleCommandBuilder performance issue

I'm currently investigating some performance issues in a .NET/Oracle application.
I've run an oracle trace file and I have noticed that the following query is being called a lot and is using a lot of resources:
select ac.constraint_name key_name, acc.column_name key_col,1
from all_cons_columns acc, all_constraints ac
where acc.owner = ac.owner
and acc.constraint_name = ac.constraint_name
and acc.table_name = ac.table_name
and ac.constraint_type = 'P'
and ac.owner = user
and ac.table_name = :TableName
order by acc.constraint_name
I have determined that this query is not being called from the application code, could it be generated by ADO.NET? The application uses OracleCommandBuilders.
Yes, I expect is is OracleCommandBuilders that is doing that: it is finding out which columns form the primary key for the given table. It needs to do this (and other metadata selects) to generate SQL statements for your application.

Resources