This is a follow up to this question:
reverse connect by?
My Database is
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Advanced Analytics,
Real Application Testing and Unified Auditing options
I have a base_data table with a self join that represents hierarchical data (master/detail) like this:
select 1000*level+1 as id
,case when mod(level,5) = 0 then 'parent_' end || 'name_'||level as name
, 1000* (5*ceil(level/5))+1 as ref_id
, case when mod(level,5) > 0 then mod(level,5) end as order_nr
from dual connect by level < 21
returns:
| ID | NAME | REF_ID | ORDER_NR |
|---|
1001 | name_1 | 5001 | 1 |
2001 | name_2 | 5001 | 2 |
3001 | name_3 | 5001 | 3 |
4001 | name_4 | 5001 | 4 |
5001 | parent_name_5 | 5001 | |
6001 | name_6 | 10001 | 1 |
7001 | name_7 | 10001 | 2 |
8001 | name_8 | 10001 | 3 |
9001 | name_9 | 10001 | 4 |
10001 | parent_name_10 | 10001 | |
11001 | name_11 | 15001 | 1 |
12001 | name_12 | 15001 | 2 |
13001 | name_13 | 15001 | 3 |
14001 | name_14 | 15001 | 4 |
15001 | parent_name_15 | 15001 | |
16001 | name_16 | 20001 | 1 |
17001 | name_17 | 20001 | 2 |
18001 | name_18 | 20001 | 3 |
19001 | name_19 | 20001 | 4 |
20001 | parent_name_20 | 20001 | |
additionally I have a refering_data table that refers the data above:
select 10000*level+2 as referrer_id
, 'referrer_name_'||level as referrer_name
, 1000* (6*level)-1999 as fk_id
from dual connect by level < 4
returns:
| REFERRER_ID | REFERRER_NAME | FK_ID |
|---|
10002 | referrer_name_1 | 1001 |
20002 | referrer_name_2 | 4001 |
30002 | referrer_name_3 | 7001 |
40002 | referrer_name_4 | 10001 |
50002 | referrer_name_5 | 13001 |
The other answer helped me to find the parent for a given ID in my base data.
What I need now is: how do I combine the base data and the referencing data so that for each entry in my referring_data table I get the corresponding entry from the base_data table and (if exists) it's parent.
Duplicate parents should be removed and the details should be ordered behind their parent in he order defined by the ORDER_NR column.
The desired output is:
| ID | NAME | REF_ID | ORDER_NR |
|---|
5001 | parent_name_5 | 5001 | |
1001 | name_1 | 5001 | 1 |
4001 | name_4 | 5001 | 4 |
10001 | parent_name_10 | 10001 | |
7001 | name_7 | 10001 | 2 |
15001 | parent_name_15 | 15001 | |
13001 | name_13 | 15001 | 3 |
I tried to adopt the other answer by doing this:
with base_data as(
select 1000*level+1 as id
,case when mod(level,5) = 0 then 'parent_' end || 'name_'||level as name
, 1000* (5*ceil(level/5))+1 as ref_id
, case when mod(level,5) > 0 then mod(level,5) end as order_nr
from dual connect by level < 21
), referring_data as(
select 10000*level+2 as referrer_id
, 'referrer_name_'||level as referrer_name
, 1000* (3*level)-1999 as fk_id
from dual connect by level < 6
)
select level, bd.*
from base_data bd
start with id in (select fk_id from referring_data)
connect by id = prior nullif(ref_id,id)
order siblings by order_nr
;
but that gives a "parent" row for each "detail row":
| LEVEL | ID | NAME | REF_ID | ORDER_NR |
|---|
1 | 1001 | name_1 | 5001 | 1 |
2 | 5001 | parent_name_5 | 5001 | |
1 | 7001 | name_7 | 10001 | 2 |
2 | 10001 | parent_name_10 | 10001 | |
1 | 13001 | name_13 | 15001 | 3 |
2 | 15001 | parent_name_15 | 15001 | |
1 | 4001 | name_4 | 5001 | 4 |
2 | 5001 | parent_name_5 | 5001 | |
1 | 10001 | parent_name_10 | 10001 | |
How do I group the result by parent_rows keeping the order of the detail rows?
Also the Parents need to be ordered by their ID.
Message was edited by: TPD-Opitz added example for referring data