Joining the tables.Aggregating and consolidating the counts - sql

enter image description hereI have two tables
Table 1-qualified players
Id_sequence
121
345
765
Table 2 - All enteries related to players Note :there are only 6 game_ids 1a,1b,1c,2a,2b,2c
id_sequence player_id game_id phone_no
121 aaa 1a 111111111
131 aaa 1b 111222111
141 aaa 1a 111112222
345 bbb 2a 222222222
656 bbb 2c 222211122
789 bbb 1c 222211122
632 bbb 2b 222222222
765 ccc 2b 333333333
897 ddd 1a 444444444
433 ddd 2c 555555444
Expected Output:
select all id_sequence from Table 1 and join Table 2.
Then select all other data related to that player_id then aggregate and consolidate the counts
player_id game id_1a game id_1b game id_1c game id_2a game id_2b game id_2c no_of _phones
aaa 2 1 3
bbb 1 1 1 1 2
ccc 1 1
Currently,I am creating a table 3 that stores the player_id obtained from joining table 1 and table 2 .Then again joining table 3 and 2.
Any thoughts and ideas will greatly help.

Test data (see also: dbfiddle)
SQL> select * from ae;
ID_SEQUENCE PLAYER_ID GAME_ID PHONE_NO
121 aaa 1a 111111111
131 aaa 1b 111222111
141 aaa 1a 111112222
345 bbb 2a 222222222
656 bbb 2c 222211122
789 bbb 1c 222211122
632 bbb 2b 222222222
765 ccc 2b 333333333
897 ddd 1a 444444444
433 ddd 2c 555555444
Query
select
dt1.*
, dt2.no_of_phones
from (
(
select game_id, player_id
from ae
) pivot
(
count( game_id ) for game_id in
(
'1a' as "game id_1a"
, '1b' as "game id_1b"
, '1c' as "game id_1c"
, '2a' as "game id_2a"
, '2b' as "game id_2b"
, '2c' as "game id_2c"
)
)
) dt1 join (
select
player_id
, count( phone_no ) no_of_phones
from ae
group by player_id
) dt2
on dt1.player_id = dt2.player_id
order by dt1.player_id
;
Result
PLAYER_ID game id_1a game id_1b game id_1c game id_2a game id_2b game id_2c NO_OF_PHONES
aaa 2 1 0 0 0 0 3
bbb 0 0 1 1 1 1 4
ccc 0 0 0 0 1 0 1
ddd 1 0 0 0 0 1 2

A PIVOT should take care of it
SQL> create table t1 ( id int);
Table created.
SQL>
SQL> insert into t1 values (121 );
1 row created.
SQL> insert into t1 values (345 );
1 row created.
SQL> insert into t1 values (765 );
1 row created.
SQL>
SQL>
SQL> create table t2 ( id int, player varchar2(10), game varchar2(10), phone int );
Table created.
SQL>
SQL> insert into t2 values (121 ,'aaa' , '1a' , 111111111);
1 row created.
SQL> insert into t2 values (131 ,'aaa' , '1b' , 111222111 );
1 row created.
SQL> insert into t2 values (141 ,'aaa' , '1a' , 111112222 );
1 row created.
SQL> insert into t2 values (345 ,'bbb' , '2a' , 222222222 );
1 row created.
SQL> insert into t2 values (656 ,'bbb' , '2c' , 222211122 );
1 row created.
SQL> insert into t2 values (789 ,'bbb' , '1c' , 222211122 );
1 row created.
SQL> insert into t2 values (632 ,'bbb' , '2b' , 222222222 );
1 row created.
SQL> insert into t2 values (765 ,'ccc' , '2b' , 333333333 );
1 row created.
SQL> insert into t2 values (897 ,'ddd' , '1a' , 444444444 );
1 row created.
SQL> insert into t2 values (433 ,'ddd' , '2c' , 555555444);
1 row created.
SQL>
SQL>
SQL> SELECT *
2 FROM (SELECT player, game, phone
3 FROM t2)
4 PIVOT (count(phone) AS cnt FOR (game) IN ('1a','1b','2a','2b','3a','3c'));
PLAYER '1a'_CNT '1b'_CNT '2a'_CNT '2b'_CNT '3a'_CNT '3c'_CNT
---------- ---------- ---------- ---------- ---------- ---------- ----------
aaa 2 1 0 0 0 0
bbb 0 0 1 1 0 0
ddd 1 0 0 0 0 0
ccc 0 0 0 1 0 0
4 rows selected.
Addenda to get NO_PHONES
SQL> SELECT *
2 FROM (SELECT player, game, phone, count( distinct phone) over ( partition by player ) as no_phones
3 FROM t2)
4 PIVOT (count(phone) AS cnt FOR (game) IN ('1a','1b','2a','2b','3a','3c'));
PLAYER NO_PHONES '1a'_CNT '1b'_CNT '2a'_CNT '2b'_CNT '3a'_CNT '3c'_CNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
ccc 1 0 0 0 1 0 0
ddd 2 1 0 0 0 0 0
aaa 3 2 1 0 0 0 0
bbb 2 0 0 1 1 0 0

Related

Using primary key of a table as foreign key in insert query

I am trying to populate data into my tables. Let's say I have three tables
TABLE_A, TABLE_B, TABLE_C.
TABLE_A has four columns, I am currently getting values for this table as follows:
INSERT INTO TABLE_A(COL_A, COL_B, COL_C, COL_D)
SELECT TABLE_A.SQ.nextval, colb AS COL_B, colc AS COL_C, cold as COL_D
FROM TABLE_D
Now I want to use the primary key of Table_A as foreign key in my other table which is TABLE_B, and primary key of TABLE_B as foreign key of TABLE_C.
The Use case is as follows I want to extract data from a table(TableX) and load it into other tables (TABLE_A, Table_Y, TABLE_Z), we have normalized TableX to three tables, and since i cannot definitely use the primary key of old table i am using sequence to generate Primary Key.
The RETURNING INTO clause can be used for this. Below is a simple example for a single row insert with tablea, tableb and tablec.
Note that this is is for a row by row operation, so you'd have to loop through table_d in your case. There is a RETURNING BULK COLLECT INTO as well to populate an array.
create sequence tablea_seq;
create sequence tableb_seq;
create sequence tablec_seq;
create table tablea (
tablea_id number
constraint tablea_tablea_id_pk primary key,
c1 varchar2(10 char)
)
;
create table tableb (
tablea_id number
constraint tableb_tablea_id_fk
references tablea on delete cascade,
tableb_id number
constraint tableb_tableb_id_pk primary key,
col1 varchar2(10 char)
);
create table tablec (
tableb_id number
constraint tablec_tableb_id_fk
references tableb on delete cascade,
tablec_id number
constraint tablec_tablec_id_pk primary key,
col1 varchar2(10 char)
);
DECLARE
l_tablea_id tablea.tablea_id%TYPE;
l_tableb_id tableb.tableb_id%TYPE;
BEGIN
INSERT INTO tablea (tablea_id,c1) VALUES (tablea_seq.NEXTVAL,'some val')
RETURNING tablea_id INTO l_tablea_id;
INSERT INTO tableb (tableb_id,tablea_id,col1)
VALUES (tableb_seq.NEXTVAL,l_tablea_id,'Foobar')
RETURNING tableb_id INTO l_tableb_id;
INSERT INTO tablec (tablec_id,tableb_id,col1)
VALUES (tableb_seq.NEXTVAL,l_tablea_id,'Foobar');
END;
/
In the same operation? If so, then you wouldn't directly use sequence value, but first store it into a local variable so that you could use it as a
primary key for table_a
foreign key value while inserting into table_b
The same goes for table_b's primary key (which will then be used as a foreign key in table_c).
Assuming this is your denormalized table_x consisting of three parent -child levels, where key_n is th e*original key of the level n and col_n their respective attribute.
select * from table_x;
KEY_1 COL_1 KEY_2 COL_2 KEY_3 COL_3
---------- ---------- ---------- ---------- ---------- ----------
100 a 101 aa 101 aaa
100 a 101 aa 102 aab
100 a 102 ab 103 aba
100 a 102 ab 104 abb
200 b 103 ba 105 baa
200 b 103 ba 106 bab
200 b 104 bb 107 bba
200 b 104 bb 108 bbb
With some analytic functions you may identify which row are to be inserted on which level and assign the new primary keys.
Here
on level n insert only row with lev_n_rn = 1
the new IDs are assigned sequentially with row_number (without a sequence)
.
with norm as (
select
row_number() over (partition by KEY_1 order by KEY_2, KEY_3) lev_1_rn,
KEY_1, COL_1,
row_number() over (partition by KEY_1,KEY_2 order by KEY_3) lev_2_rn,
KEY_2, COL_2,
row_number() over (partition by KEY_1,KEY_2,KEY_3 order by COL_3) lev_3_rn,
KEY_3, COL_3
from table_x)
select
lev_1_rn,
sum(case when lev_1_rn = 1 then 1 end) over (order by KEY_1) id1,
KEY_1, COL_1,
lev_2_rn,
sum(case when lev_2_rn = 1 then 1 end) over (order by KEY_1, KEY_2) id2,
KEY_2, COL_2,
lev_3_rn,
sum(case when lev_3_rn = 1 then 1 end) over (order by KEY_1, KEY_2, KEY_3) id3,
KEY_3, COL_3
from norm;
LEV_1_RN ID1 KEY_1 COL_1 LEV_2_RN ID2 KEY_2 COL_2 LEV_3_RN ID3 KEY_3 COL_3
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1 1 100 a 1 1 101 aa 1 1 101 aaa
2 1 100 a 2 1 101 aa 1 2 102 aab
3 1 100 a 1 2 102 ab 1 3 103 aba
4 1 100 a 2 2 102 ab 1 4 104 abb
1 2 200 b 1 3 103 ba 1 5 105 baa
2 2 200 b 2 3 103 ba 1 6 106 bab
3 2 200 b 1 4 104 bb 1 7 107 bba
4 2 200 b 2 4 104 bb 1 8 108 bbb
The rest is a task for INSERT ALL using the above query and constraining the relevant rows and attributes (pk + fk) for each level
insert all
when LEV_1_RN = 1 then
into table_a (id, key_1, col_1) values(ID1, KEY_1, COL_1)
when LEV_2_RN = 1 then
into table_b (id, fk_id, key_2, col_2) values(ID2, ID1, KEY_2, COL_2)
when LEV_3_RN = 1 then
into table_c (id, fk_id, key_3, col_3) values(ID3, ID2, KEY_3, COL_3)
with norm as (
select
row_number() over (partition by KEY_1 order by KEY_2, KEY_3) lev_1_rn,
KEY_1, COL_1,
row_number() over (partition by KEY_1,KEY_2 order by KEY_3) lev_2_rn,
KEY_2, COL_2,
row_number() over (partition by KEY_1,KEY_2,KEY_3 order by COL_3) lev_3_rn,
KEY_3, COL_3
from table_x)
select
lev_1_rn,
sum(case when lev_1_rn = 1 then 1 end) over (order by KEY_1) id1,
KEY_1, COL_1,
lev_2_rn,
sum(case when lev_2_rn = 1 then 1 end) over (order by KEY_1, KEY_2) id2,
KEY_2, COL_2,
lev_3_rn,
sum(case when lev_3_rn = 1 then 1 end) over (order by KEY_1, KEY_2, KEY_3) id3,
KEY_3, COL_3
from norm;
Producing this result
select * from table_a;
ID KEY_1 COL_1
---------- ---------- ----------
1 100 a
2 200 b
select * from table_b;
ID FK_ID KEY_2 COL_2
---------- ---------- ---------- ----------
1 1 101 aa
2 1 102 ab
3 2 103 ba
4 2 104 bb
select * from table_c;
ID FK_ID KEY_3 COL_3
---------- ---------- ---------- ----------
2 1 102 aab
4 2 104 abb
6 3 106 bab
8 4 108 bbb
I'd assume this will be (for a large table) the most effective transformation (as you ommit loops and lookups).
If you maintain the new table is a signle user mode (no multiuser) you actually do not need sequences, but if you like you may deploy them after the transformation with propper set initial values.

I would like to get the data 'order by' for each select query and then combine them using 'Union All'

I have two temp tables (#TempA, #TempB). each temp table has few records with the formorder 1, 2 and 3. Each Order has multiple records/rows.
For Example:
TempA
===========================
C1 C2 C3 FormOrder
===========================
abc xyz lmn 1
------------------------
anc ppl nmp 2
----------------------
acc bbl mnp 3
-----------------------
Similarly, TempB has few records in the same format.
while combining these two Temp tables with using union all, I am getting the data. but the Data is not coming in order from the #TempA table.
I have tried adding 'Order by' at the end of the select query, but I am getting results in different way.
Without using Order By:
select * from #TempA
Union All
select * from #TempB
Results:
===========================
C1 C2 C3 FormOrder
===========================
abc xyz lmn 1
-----------------------
acc bbl mnp 3
----------------------
anc ppl nmp 2
----------------------
xyz ccc nnn 1
------------------------
xyn klm uul 2
------------------------
cpp klm rnp 3
------------------------
Here the order from the #TempA is missing. So when I tried with Order By
select * from #TempA
Union All
select * from #TempB
Order by FormOrder
Results:
==========================
C1 C2 C3 FormOrder
============================
abc xyz lmn 1
---------------------------
xyz ccc nnn 1
----------------------------
anc ppl nmp 2
----------------------------
xyn klm uul 2
--------------------------
acc bbl mnp 3
-----------------------------
cpp klm rnp 3
-------------------------
I am getting the above Order, but I am expecting the Order as 1,2,3 and them from TempA 1,2, 3 from TempB.
============================
C1 C2 C3 FormOrder
============================
abc xyz lmn 1
--------------------------
anc ppl nmp 2
-------------------------
acc bbl mnp 3
-----------------------
xyz ccc nnn 1
-------------------------
xyn klm uul 2
---------------------------
cpp klm rnp 3
------------------------
How can I achieve this? Any help much appreciated.
You can do the following:
SELECT *
FROM (
SELECT 'A' AS Source, * from #TempA
Union All
select 'B', * from #TempB
) SEL
Order by Source
, FormOrder
Of course, you shouldn't use SELECT *, because one of the tables could change structure.
you can try this:
Declare #TempA Table(C1 varchar(5),C2 varchar(5),C3 varchar(5), FormOrder int)
Declare #TempB Table(C1 varchar(5),C2 varchar(5),C3 varchar(5), FormOrder int)
insert into #TempA
SELECT 'abc','xyz','mn',1 Union All
SELECT 'anc','ppl','mp',2 Union All
SELECT 'acc','bbl','np',3
insert into #TempB
SELECT 'xyz','ccc','nnn',1 Union All
SELECT 'xyn','klm','uul',2 Union All
SELECT 'cpp','klm','rnp',3
;with cte
As
(
Select C1,C2,C3,FormOrder,NULL as FormOrder2 from #TempA
Union All
Select C1,C2,C3,NULL as FormOrder, FormOrder as FormOrder2 from #TempB
)
Select C1,C2,C3,ISNULL(FormOrder,FormOrder2) As SortOrder
from cte order by FormOrder2,FormOrder
create table tempA(
c1 varchar2(10),
c2 varchar2(10),
c3 varchar2(10),
formOrder number(2)
);
create table tempB(
c1 varchar2(10),
c2 varchar2(10),
c3 varchar2(10),
formOrder number(2)
);
insert into tempA values('abc','xyz','lmn',1);
insert into tempA values('anc','ppc','nmp',2);
insert into tempA values('acc','bbl','mnp',3);
insert into tempB values('xyz','ccc','nnn',1);
insert into tempB values('xyn','klm','nnl',2);
insert into tempB values('cpp','klm','rnp',3);
select * from tempA
union all
select * from tempB;
C1 C2 C3 FORMORDER
---------- ---------- ---------- ----------
abc xyz lmn 1
anc ppc nmp 2
acc bbl mnp 3
xyz ccc nnn 1
xyn klm nnl 2
cpp klm rnp 3

update tables based on rows in it and other table

Below are the tables that i work on -
table_ctrl_result -
seq_id req_id ctrl_id c1 c2 status
1 1 C001 DES 380 NULL
2 1 C001 ABC 0 NULL
3 1 C001 EDC 0 NULL
TABLE_CTRL_MSTR -
ctrl_id tolerance symbol
c001 1000 <
Below is the expected result,
seq_id req_id ctrl_id c1 c2 status
1 1 C001 DES 380 PASS
2 1 C001 ABC 0 PASS
3 1 C001 EDC 0 PASS
I am using the query thats mentioned in the comment , but I am getting the below result.,
seq_id req_id ctrl_id c1 c2 status
1 1 C001 DES 380 PASS
2 1 C001 ABC 0 FAIL
3 1 C001 EDC 0 FAIL
SQL:
update ca_demo.table_ctrl_result a
set a.STATUS = (
select
(case
when b.symbol = '>' and a.c2 > b.tolerance or b.symbol = '<' and a.c2 < b.tolerance or b.symbol = '=' and a.c2 = b.tolerance
then 'PASS'
else 'FAIL'
end)
from ca_demo.table_ctrl_mstr b
where a.ctrl_id = b.ctrl_id
);
I'm missing something. Please assist.
Test case:
SQL> create table ctrl_result
2 (seq_id number,
3 ctrl_id varchar2(4),
4 c1 varchar2(3),
5 c2 number,
6 status varchar2(5));
Table created.
SQL> create table ctrl_mstr
2 (ctrl_id varchar2(4),
3 tolerance number,
4 symbol varchar2(2));
Table created.
SQL> insert into ctrl_result
2 select 1, 'C001', 'DES', 380, null from dual union all
3 select 2, 'C001', 'ABC', 0, null from dual union all
4 select 3, 'C001', 'EDC', 0, null from dual union all
5 select 4, 'C002', 'XXX', 500, null from dual union all
6 select 5, 'C002', 'YYY', 100, null from dual;
5 rows created.
SQL> insert into ctrl_mstr
2 select 'C001', 1000, '<' from dual union all
3 select 'C002', 200, '>' from dual;
2 rows created.
Some querying & the result:
SQL> merge into ctrl_result c
2 using (select r.seq_id, r.ctrl_id, r.c2,
3 m.tolerance, m.symbol,
4 --
5 case when m.symbol = '<' and r.c2 < m.tolerance then 'PASS'
6 when m.symbol = '<' and r.c2 >= m.tolerance then 'FAIL'
7 when m.symbol = '>' and r.c2 > m.tolerance then 'PASS'
8 when m.symbol = '>' and r.c2 <= m.tolerance then 'FAIL'
9 else 'NONE'
10 end status
11 from ctrl_result r join ctrl_mstr m on m.ctrl_id = r.ctrl_id
12 ) x
13 on (c.seq_id = x.seq_id)
14 when matched then update set c.status = x.status;
5 rows merged.
SQL> select * From ctrl_Result order by seq_id;
SEQ_ID CTRL C1 C2 STATU
---------- ---- --- ---------- -----
1 C001 DES 380 PASS
2 C001 ABC 0 PASS
3 C001 EDC 0 PASS
4 C002 XXX 500 PASS
5 C002 YYY 100 FAIL
SQL>

How to get the final parent id column in oracle connect by sql

1 Create table like this
CREATE TABLE oracle_connet_by_test (
item_id NUMBER PRIMARY KEY,
parent_id NUMBER,
item_desc VARCHAR2(8));
INSERT INTO oracle_connet_by_test VALUES(1, 0, 'AAA');
INSERT INTO oracle_connet_by_test VALUES(2, 0, 'BBB');
INSERT INTO oracle_connet_by_test VALUES(3, 1, 'CCC');
INSERT INTO oracle_connet_by_test VALUES(4, 2, 'DDD');
INSERT INTO oracle_connet_by_test VALUES(5, 1, 'EEE');
INSERT INTO oracle_connet_by_test VALUES(6, 3, 'FFF');
INSERT INTO oracle_connet_by_test VALUES(7, 3, 'GGG');
commit;
2 When I ran this script, the output will be
SQL> SELECT LEVEL,
2 ITEM_ID,
3 PARENT_ID, LPAD(' ', 4 * (LEVEL - 1)) || ITEM_DESC AS ITEM_DESC
4 FROM ORACLE_CONNET_BY_TEST
5 START WITH parent_Id = 0
6 CONNECT BY PRIOR ITEM_ID = PARENT_ID
7 ;
LEVEL ITEM_ID PARENT_ID ITEM_DESC
---------- ---------- ---------- -----------
1 1 0 AAA
2 3 1 CCC
3 6 3 FFF
3 7 3 GGG
2 5 1 EEE
1 2 0 BBB
2 4 2 DDD
3 The QUESTION: If I want this result, how should I write the code?
LEVEL ITEM_ID PARENT_ID ITEM_DESC SUPER_ID
---------- ---------- ---------- ---------------- ----------
1 1 0 AAA 1
2 3 1 CCC 1
3 6 3 FFF 1
3 7 3 GGG 1
2 5 1 EEE 1
1 2 0 BBB 2
2 4 2 DDD 2
use connect_by_root:
SELECT LEVEL,
ITEM_ID,
PARENT_ID, LPAD(' ', 4 * (LEVEL - 1)) || ITEM_DESC AS ITEM_DESC
, connect_by_root item_id AS SUPER_ID
FROM ORACLE_CONNET_BY_TEST
START WITH parent_Id = 0
CONNECT BY PRIOR ITEM_ID = PARENT_ID
;

Multiple left-outer join results in duplicated rows

I have a big table having Incidents. With this I want to attach values from Incident Attachment and Incident Comments. I have used Left outer join as there may or may not be any comments OR attachment for a Incident.
Now when I use multiple outer join i get duplicated rows.
There is a incidentID value that is common for all the tables
INC1 ATT1 COMMENT1
INC1 ATT1 COMMENT2
INC1 ATT2 COMMENT1
INC1 ATT2 COMMENT2
But actually the output should be:
INC1 ATT1 COMMENT1
INC1 ATT2 COMMENT2
so that the attachment and the comment values are independent when attaching themselves to the incident table.
select inc,att.attname,comment.commenttext
from inc
left outer join att inc.incidentID=att.incidentID
left outer join comment inc.incidentID=comment .incidentID
Is this possible?
One of the things I'm taking away from your responses so far is that, for a given incident, there's no direct relationship between its attachments and its comments.
If I understand that correctly, you want to treat an incident as a simple "container" for attachments and comments, and you just want a listing of each. Which
attachment happens to appear in the same row as a particular comment is incidental to you.
TEST DATA:
SQL> CREATE TABLE inc (incidentid NUMBER, incname VARCHAR2(20));
Table created.
SQL> INSERT INTO inc VALUES (1,'incident 1');
1 row created.
SQL> INSERT INTO inc VALUES (2,'incident 2');
1 row created.
SQL> CREATE TABLE att (att_id NUMBER, incidentid NUMBER, attname VARCHAR2(20));
Table created.
SQL> INSERT INTO att VALUES (101, 1, 'attachment 1');
1 row created.
SQL> INSERT INTO att VALUES (102, 1, 'attachment 2');
1 row created.
SQL> INSERT INTO att VALUES (103, 1, 'attachment 3');
1 row created.
SQL> INSERT INTO att VALUES (104, 1, 'attachment 4');
1 row created.
SQL> INSERT INTO att VALUES (105, 1, 'attachment 5');
1 row created.
SQL> INSERT INTO att VALUES (110, 2, 'attachment A');
1 row created.
SQL> INSERT INTO att VALUES (111, 2, 'attachment B');
1 row created.
SQL> INSERT INTO att VALUES (112, 2, 'attachment C');
1 row created.
SQL> CREATE TABLE comments (comment_id NUMBER, incidentid NUMBER, commenttext VARCHAR2(20));
Table created.
SQL> INSERT INTO comments VALUES (201, 1, 'first comment');
1 row created.
SQL> INSERT INTO comments VALUES (202, 1, 'second comment');
1 row created.
SQL> INSERT INTO comments VALUES (203, 1, 'third comment');
1 row created.
PROPOSED QUERY:
SQL> WITH a AS (
2 SELECT att.incidentid
3 , COUNT(att.att_id) rows_per_incident
4 FROM att
5 GROUP BY att.incidentid
6 UNION ALL
7 SELECT comments.incidentid
8 , COUNT(comments.comment_id) rows_per_incident
9 FROM comments
10 GROUP BY comments.incidentid
11 )
12 , b AS (
13 SELECT inc.incidentid
14 , inc.incname
15 , ROW_NUMBER()
16 OVER (PARTITION BY inc.incidentid ORDER BY NULL) row_num
17 FROM inc
18 , (SELECT ROWNUM multiplier FROM DUAL CONNECT BY LEVEL <= (SELECT MAX(rows_per_incident) FROM a))
19 )
20 , c AS (
21 SELECT att.att_id
22 , att.incidentid
23 , att.attname
24 , ROW_NUMBER()
25 OVER (PARTITION BY att.incidentid ORDER BY att.att_id) att_rn
26 FROM att
27 )
28 , d AS (
29 SELECT comments.comment_id
30 , comments.incidentid
31 , comments.commenttext
32 , ROW_NUMBER()
33 OVER (PARTITION BY comments.incidentid ORDER BY comments.comment_id) comm_rn
34 FROM comments
35 )
36 , e AS (
37 SELECT c.incidentid
38 , c.att_id
39 , c.attname
40 , c.att_rn rn
41 , d.comment_id
42 , d.commenttext
43 FROM c
44 , d
45 WHERE c.incidentid = d.incidentid (+)
46 AND c.att_rn = d.comm_rn (+)
47 UNION ALL
48 SELECT TO_NUMBER(NULL) incidentid
49 , TO_NUMBER(NULL) att_id
50 , NULL attname
51 , d.comm_rn rn
52 , d.comment_id
53 , d.commenttext
54 FROM d
55 WHERE NOT EXISTS (SELECT NULL
56 FROM c
57 WHERE c.incidentid = d.incidentid
58 AND c.att_rn = d.comm_rn)
59 )
60 , f AS (
61 SELECT b.incidentid
62 , b.incname
63 , b.row_num
64 , e.att_id
65 , e.attname
66 , e.comment_id
67 , e.commenttext
68 FROM b
69 LEFT OUTER JOIN e ON b.incidentid = e.incidentid
70 AND b.row_num = e.rn
71 )
72 SELECT f.incidentid
73 , f.incname
74 , f.att_id
75 , f.attname
76 , f.comment_id
77 , f.commenttext
78 FROM f
79 WHERE NOT (f.att_id IS NULL AND f.comment_id IS NULL)
80 ORDER BY f.incidentid
81 , f.row_num
82 ;
INCIDENTID INCNAME ATT_ID ATTNAME COMMENT_ID COMMENTTEXT
---------- -------------------- ---------- -------------------- ---------- --------------------
1 incident 1 101 attachment 1 201 first comment
1 incident 1 102 attachment 2 202 second comment
1 incident 1 103 attachment 3 203 third comment
1 incident 1 104 attachment 4
1 incident 1 105 attachment 5
2 incident 2 110 attachment A
2 incident 2 111 attachment B
2 incident 2 112 attachment C
8 rows selected.
SQL>