Skip to Main Content
  • Questions
  • Ordering interdependent tables using their Primary - Foreign key relationships

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Fatai.

Asked: October 31, 2000 - 6:23 am UTC

Last updated: June 17, 2006 - 4:11 pm UTC

Version: 7.2.3.0.0

Viewed 1000+ times

You Asked

I have a number of tables in my user_tables dictionary, All of which are directly or indirectly dependent on each other by virtue of their Primary - Foreign /key relationships.

Is there any code around that can help me order these tables such that if I want to DELETE or INSERT into these tables, I will be able to achieve this in the right order without violating the child - Parent key constraints.

I have tried manually doing this but to no avail.

I also though about using the walking tree method which I don't think I am doing properly

Please Any help will be appreciated.

and Tom said...

For the delete, I would implement the foreign keys with ON DELETE CASCADE and just delete the parent table.

For the inserts -- well, I cannot imagine a situation where I would not inheritly KNOW what the relationship where when inserting but ....

In 8.0 and later, i would use deferred constraints. In that fashion, I can insert in any order and the validation of the constraint is deferred until you commit. Since you have 7.2, that is not workable for you...

You should be aware that there are cases where you cannot get the right order. It is totally possible (common even) for A to have a foreign key to B and B to A. In this case -- the only solution is to insert NULL foreign keys and update them after the fact -- especially when putting that first row in there!

What might work for you is a query against user_constraints. We have to use a temporary table since the connect by won't work on the join. We can use a permanent temporary table if you surround the INSERT+OPEN Query with a savepoint and rollback to savepoint as I have below. That way, the temp table always appears to be empty.


ops$tkyte@ORA8I.WORLD> create table p ( pk int primary key );

Table created.

ops$tkyte@ORA8I.WORLD> create table c1( pk int primary key,
2 fk int references p );

Table created.

ops$tkyte@ORA8I.WORLD> create table c2( pk int primary key,
2 fk int references c1 );

Table created.

ops$tkyte@ORA8I.WORLD> create table c3( pk int primary key,
2 fk int references p );

Table created.

ops$tkyte@ORA8I.WORLD> create table c4 ( pk int primary key,
2 fk int references c3 );

Table created.

ops$tkyte@ORA8I.WORLD> create table c5( pk int primary key,
2 fk int references c4 );

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> drop table temp;

Table dropped.

ops$tkyte@ORA8I.WORLD> create table temp ( child varchar2(30), parent varchar2(30) );

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> savepoint foo;

Savepoint created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into temp
2 select a.table_name child, b.table_name parent
3 from user_constraints a, user_constraints b
4 where a.constraint_type = 'R'
5 and a.r_constraint_name = b.constraint_name
6 /

6 rows created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select parent, rpad( '*', level, '*' ) || child child
2 from temp
3 start with parent = 'P'
4 connect by prior child = parent
5 /

PARENT CHILD
------------------------------ --------------------
P *C1
C1 **C2
P *C3
C3 **C4
C4 ***C5

ops$tkyte@ORA8I.WORLD> rollback to foo;

Rollback complete.

ops$tkyte@ORA8I.WORLD>

Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Srinivas, May 15, 2001 - 2:55 pm UTC


10G

OTN, June 17, 2006 - 11:30 am UTC

Tom

Out database is 10G, is there a better way of doing the above in 10G.

We dont use deferred constraints though.

Tom Kyte
June 17, 2006 - 4:11 pm UTC

ops$tkyte@ORA10GR2> l
  1  with temp
  2  as
  3  (
  4  select a.table_name child, b.table_name parent
  5    from user_constraints a, user_constraints b
  6   where a.constraint_type = 'R'
  7     and a.r_constraint_name = b.constraint_name
  8  )
  9  select parent, rpad( '*', level, '*'  ) || child child
 10    from temp
 11   start with parent = 'P'
 12*  connect by prior child = parent
ops$tkyte@ORA10GR2> /

PARENT                         CHILD
------------------------------ ----------
P                              *C1
C1                             **C2
P                              *C3
C3                             **C4
C4                             ***C5


should be ok in 9ir2 and above...

same caveats apply - tables with multiple parents, recursive relationships....