I'm having issues on building a tree starting from a table.
I'm following the tutorial from D.Fontaine but something is wrong in my query.
here is a subset of rows from this table:
abs=# select * from myproj_loparentrelation where root_id = '57b2e67b-5862-499a-a471-0f2f6b23440e' order by level ASC;
id | root_id | level | display_sequence | lo_id | parent_id
--------+--------------------------------------+-------+------------------+--------------------------------------+--------------------------------------
90468 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 2 | 1 | 5c51558b-1180-495f-88c3-f7af49bafcf3 | 57b2e67b-5862-499a-a471-0f2f6b23440e
55209 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 2 | 16 | 3962f997-9e14-4cac-a95f-dc20c077a531 | 57b2e67b-5862-499a-a471-0f2f6b23440e
14890 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 3 | 17 | 0f335cd1-74d0-4a5e-831d-1aba0c0dc396 | 3962f997-9e14-4cac-a95f-dc20c077a531
116513 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 3 | 4 | 78b6cac3-307f-449a-bb3c-fe4442f4d1e8 | 5c51558b-1180-495f-88c3-f7af49bafcf3
122691 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 3 | 6 | 7ecb01da-078a-49b9-b488-86dc6bb24ab4 | 5c51558b-1180-495f-88c3-f7af49bafcf3
95729 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 3 | 14 | 62e889fe-b0e6-4fd4-a89f-512a1f31e210 | 5c51558b-1180-495f-88c3-f7af49bafcf3
141390 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 3 | 2 | 932353b7-bb63-4bad-87e7-70bcebcbbc98 | 5c51558b-1180-495f-88c3-f7af49bafcf3
96022 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 3 | 26 | 6346657d-a41e-45ab-87bc-abf32a8c616c | 3962f997-9e14-4cac-a95f-dc20c077a531
61116 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 22 | 3f07cece-0a7c-411e-b7d1-0370d18c6405 | 0f335cd1-74d0-4a5e-831d-1aba0c0dc396
72097 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 5 | 49c43039-84e6-4f36-a8a1-5f57ad1bc67e | 78b6cac3-307f-449a-bb3c-fe4442f4d1e8
81260 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 15 | 51e9ce01-9c90-437a-b17c-8b0b19c3a2b4 | 62e889fe-b0e6-4fd4-a89f-512a1f31e210
84177 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 12 | 553150c1-ff43-44e0-a52d-d6361813de73 | 7ecb01da-078a-49b9-b488-86dc6bb24ab4
89331 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 24 | 5b1ede40-66a6-4320-be79-69f0a4d0340e | 0f335cd1-74d0-4a5e-831d-1aba0c0dc396
111377 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 21 | 73f05e3c-012e-4b41-acc0-14791c83f710 | 0f335cd1-74d0-4a5e-831d-1aba0c0dc396
114868 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 33 | 778bf627-e83f-4385-bbb9-3537d45d18b6 | 6346657d-a41e-45ab-87bc-abf32a8c616c
129785 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 27 | 8650b402-bb6f-4be2-9585-800d189ded83 | 6346657d-a41e-45ab-87bc-abf32a8c616c
151263 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 10 | 9f29806f-d04d-4952-9743-9b2eedeecfee | 7ecb01da-078a-49b9-b488-86dc6bb24ab4
152546 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 34 | a0958fb5-21c2-440b-8dc9-02659b34691e | 6346657d-a41e-45ab-87bc-abf32a8c616c
158562 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 13 | a7f96063-e78e-4248-a512-68d726b0ff09 | 7ecb01da-078a-49b9-b488-86dc6bb24ab4
165779 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 7 | aeacbddd-37d6-4eda-9695-bace3406f415 | 7ecb01da-078a-49b9-b488-86dc6bb24ab4
177880 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 28 | bc18337c-899c-416b-91e4-93e4c7699d58 | 6346657d-a41e-45ab-87bc-abf32a8c616c
188650 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 11 | c6a82ea7-2156-492e-9f0f-a73c36afba70 | 7ecb01da-078a-49b9-b488-86dc6bb24ab4
204117 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 30 | d7924927-55c3-4085-bdd6-5420ef7162a9 | 6346657d-a41e-45ab-87bc-abf32a8c616c
10528 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 19 | 0be4c51c-3d52-499e-98fb-3dac9b2b1e49 | 0f335cd1-74d0-4a5e-831d-1aba0c0dc396
223079 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 3 | ebb92498-a730-4b61-b1dd-44696aae4a8e | 932353b7-bb63-4bad-87e7-70bcebcbbc98
11987 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 29 | 0ccd9922-85fa-45de-bd87-257b77e2a5a3 | 6346657d-a41e-45ab-87bc-abf32a8c616c
22808 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 32 | 17f12743-e0c4-4f32-a1d6-0e680fa762d5 | 6346657d-a41e-45ab-87bc-abf32a8c616c
28627 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 31 | 1eb6653a-de11-42a2-9766-4222996ff75e | 6346657d-a41e-45ab-87bc-abf32a8c616c
35421 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 20 | 26418eb9-22d4-41f4-a117-ae1884987080 | 0f335cd1-74d0-4a5e-831d-1aba0c0dc396
36110 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 25 | 27198280-5cff-462c-87be-5fb8b6a7b309 | 0f335cd1-74d0-4a5e-831d-1aba0c0dc396
46312 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 23 | 319838f6-aebc-460e-ae77-009858f2f858 | 0f335cd1-74d0-4a5e-831d-1aba0c0dc396
48878 | 57b2e67b-5862-499a-a471-0f2f6b23440e | 4 | 9 | 33bf5a6f-5b72-4bf0-9e1b-a68f7ad69a64 | 7ecb01da-078a-49b9-b488-86dc6bb24ab4
root is 57b2e67b-5862-499a-a471-0f2f6b23440e
under the root, there are two children 5c51558b-1180-495f-88c3-f7af49bafcf3 and 3962f997-9e14-4cac-a95f-dc20c077a531
each one of those has other children and so on.
the expected result would be something like:
[
{'Name': '57b2e67b-5862-499a-a471-0f2f6b23440e',
'Sub Classes': [
{'Name': '5c51558b-1180-495f-88c3-f7af49bafcf3',
'Subclasses': [
]},
{'Name': '3962f997-9e14-4cac-a95f-dc20c077a531',
'Subclasses': [
{'Name': '5c51558b-1180-495f-88c3-f7af49bafcf3',
'Subclasses': [
...
]}
]}
}
]
but it's not so I'm messing up something. here's the query:
with recursive rels_from_parents as
(
select sel.lo_id, '{}'::uuid[] as parents, sel.level as _level
from (select * from myproj_loparentrelation where root_id = '57b2e67b-5862-499a-a471-0f2f6b23440e') as sel
where sel.parent_id = sel.root_id
union all
select c.lo_id, parents || c.parent_id, c.level as _level
from rels_from_parents p
join myproj_loparentrelation c
on c.parent_id = p.lo_id
where not c.lo_id = any(parents)
),
rels_from_children as
(
select c.parent_id,
json_agg(jsonb_build_object('lo_id', c.lo_id::text))::jsonb as js
from rels_from_parents tree
join myproj_loparentrelation c using(lo_id)
where level > 0 and not lo_id = any(parents)
group by c.parent_id
union all
select c.parent_id,
jsonb_build_object('Name', c.lo_id::text)
|| jsonb_build_object('Sub Classes', js) as js
from rels_from_children tree
join myproj_loparentrelation c on c.lo_id = tree.parent_id
)
select jsonb_pretty(jsonb_agg(js))
from rels_from_children;
can anyone provide help with that?
demo: db<>fiddle
WITH RECURSIVE tree(lo_id, ancestor, child, path, json) AS (
SELECT
t1.lo_id,
NULL::text,
t2.lo_id,
'{Subclasses}'::text[] || (row_number() OVER (PARTITION BY t1.lo_id ORDER BY t2.display_sequence) - 1)::text,
jsonb_build_object('Name', t2.lo_id, 'Subclasses', array_to_json(ARRAY[]::text[]))
FROM test t1
LEFT JOIN test t2 ON t1.lo_id = t2.parent_id
WHERE t1.parent_id IS NULL
UNION
SELECT
t1.lo_id,
t1.parent_id,
t2.lo_id,
tree.path || '{Subclasses}' || (row_number() OVER (PARTITION BY t1.lo_id ORDER BY t2.display_sequence) - 1)::text,
jsonb_build_object('Name', t2.lo_id, 'Subclasses', array_to_json(ARRAY[]::text[]))
FROM test t1
LEFT JOIN test t2 ON t1.lo_id = t2.parent_id
INNER JOIN tree ON (t1.lo_id = tree.child)
WHERE t1.parent_id = tree.lo_id
)
SELECT
child as lo_id, path, json
FROM tree
WHERE child IS NOT NULL ORDER BY path
Since you cannot fill a final JSON object in a recursive structure, you'll need a function for holding a global variable:
CREATE OR REPLACE FUNCTION json_tree() RETURNS jsonb AS $$
DECLARE
_json_output jsonb;
_temprow record;
BEGIN
SELECT
jsonb_build_object('Name', lo_id, 'Subclasses', array_to_json(ARRAY[]::text[]))
INTO _json_output
FROM test
WHERE parent_id IS NULL;
FOR _temprow IN
-- <the query from above>
LOOP
SELECT jsonb_insert(_json_output, _temprow.path, _temprow.json) INTO _json_output;
END LOOP;
RETURN _json_output;
END;
$$ LANGUAGE plpgsql;
Because the solution is quiet similar as this one, please look HERE for further explanation.
Related
Suppose we have these two tables.
TABLE1:
|column_1 | ... |
--------------------
| 'a' | ... |
| 'b' | ... |
| 'c' | ... |
| 'd' | ... |
| 'e' | ... |
TABLE_2:
|column_1 | ... |
--------------------
| 1 | ... |
| 2 | ... |
| 3 | ... |
| 4 | ... |
| 5 | ... |
I want to pair all rows of TABLE_1 with some random columns from TABLE_2 where each pair is gonna have a random amount of distinct rows from TABLE_2 (range 1,2,3)
An output could be:
|column_1 | column_2 |
---------------------------
| 'a' | 1 |
| 'a' | 2 |
| 'a' | 5 |
| 'b' | 5 |
| 'c' | 3 |
| 'c' | 4 |
| 'd' | 3 |
| 'e' | 3 |
| 'e' | 5 |
| 'e' | 1 |
JOIN LATERAL
did the thing for me.
SELECT *
FROM TABLE1
LEFT JOIN LATERAL(
SELECT *
FROM TABLE2 LIMIT FLOOR(RANDOM() * 3 + 1)) a
ON TRUE
I have a table having data as shown below,
+-------+----------------+----------------+
| Id | HierUnitId | ObjectNumber |
+-------+----------------+----------------+
| 10 | 3599 | 1 |
| 10 | 3599 | 2 |
| 20 | 3599 | 3 |
| 20 | 3599 | 4 |
| 20 | 3599 | 1 |
| 30 | 3599 | 2 |
| 30 | 3599 | 3 |
+-------+----------------+----------------+
I have a select query
SELECT ID FROM TEST
FETCH NEXT :LIMIT ROWS ONLY
Now I want to limit the number of rows using the value of limit.
When the value of Limit is 2 I want two distinct id's i.e up to 5 rows. However, from query I will get only two rows having 10 as the id. Can someone help me in limiting the rows using distinct id?
What i want is total number of distinct id in the output is limit.
Use the DENSE_RANK analytic function to number the rows based on the unique/distinct ID values and then filter on that:
SELECT id
FROM (
SELECT ID,
DENSE_RANK() OVER (ORDER BY id) AS rnk
FROM test
)
WHERE rnk <= 2;
Which, for the sample data:
CREATE TABLE test (Id, HierUnitId, ObjectNumber ) AS
SELECT 10, 3599, 1 FROM DUAL UNION ALL
SELECT 10, 3599, 2 FROM DUAL UNION ALL
SELECT 20, 3599, 3 FROM DUAL UNION ALL
SELECT 20, 3599, 4 FROM DUAL UNION ALL
SELECT 20, 3599, 1 FROM DUAL UNION ALL
SELECT 30, 3599, 2 FROM DUAL UNION ALL
SELECT 30, 3599, 3 FROM DUAL;
Outputs:
ID
10
10
20
20
20
db<>fiddle here
As you said in the comment, you need to be able to define how many distinct ids should be shown. For that case i'd recommend you to find those ids first (see the distinct_ids part) and fetch all the lines you needed afterwards
with distinct_ids as (
select distinct id
from test_data
order by id
fetch first :limit rows only)
select id
from test_data td
join distinct_ids di
on td.id = di.id
If you need some distinct IDs without any particular order, then you may put fetch next ... into the subquery with distinct keyword. Index on ID column will be suitable to avoid two full table scans (I assume that ID cannot be null)
select /*+gather_plan_statistics*/
*
from t
where id in (
select distinct id
from t
where id is not null
fetch next 2 rows only
)
ID | HIERUNITID | OBJECTNUMBER
-: | ---------: | -----------:
1 | 3599 | 1
1 | 3599 | 2
2 | 3599 | 3
2 | 3599 | 4
2 | 3599 | 1
select *
from table(dbms_xplan.display_cursor(
format => 'ALL -PROJECTION -ALIAS ALLSTATS LAST'
))
| PLAN_TABLE_OUTPUT |
| :------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SQL_ID 2sqqq53kpy5rj, child number 0 |
| ------------------------------------- |
| select /*+gather_plan_statistics*/ * from t where id in ( select |
| distinct id from t where id is not null fetch next 2 rows only ) |
| |
| Plan hash value: 534568331 |
| |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| | 0 | SELECT STATEMENT | | 1 | | | 5 (100)| | 5 |00:00:00.01 | 3 | | | | |
| | 1 | MERGE JOIN SEMI | | 1 | 5 | 115 | 5 (40)| 00:00:01 | 5 |00:00:00.01 | 3 | | | | |
| | 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 7 | 70 | 2 (0)| 00:00:01 | 6 |00:00:00.01 | 2 | | | | |
| | 3 | INDEX FULL SCAN | T_IX | 1 | 7 | | 1 (0)| 00:00:01 | 6 |00:00:00.01 | 1 | | | | |
| |* 4 | SORT UNIQUE | | 6 | 2 | 26 | 3 (67)| 00:00:01 | 5 |00:00:00.01 | 1 | 2048 | 2048 | 2048 (0)| |
| | 5 | VIEW | VW_NSO_1 | 1 | 2 | 26 | 2 (50)| 00:00:01 | 2 |00:00:00.01 | 1 | | | | |
| |* 6 | VIEW | | 1 | 2 | 20 | 2 (50)| 00:00:01 | 2 |00:00:00.01 | 1 | | | | |
| |* 7 | WINDOW NOSORT STOPKEY | | 1 | 3 | 39 | 2 (50)| 00:00:01 | 2 |00:00:00.01 | 1 | 73728 | 73728 | | |
| | 8 | VIEW | | 1 | 3 | 39 | 2 (50)| 00:00:01 | 2 |00:00:00.01 | 1 | | | | |
| | 9 | SORT UNIQUE NOSORT | | 1 | 3 | 9 | 2 (50)| 00:00:01 | 2 |00:00:00.01 | 1 | | | | |
| |* 10 | INDEX FULL SCAN | T_IX | 1 | 7 | 21 | 1 (0)| 00:00:01 | 6 |00:00:00.01 | 1 | | | | |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| |
| Predicate Information (identified by operation id): |
| --------------------------------------------------- |
| |
| 4 - access("ID"="ID") |
| filter("ID"="ID") |
| 6 - filter("from$_subquery$_004"."rowlimit_$$_rownumber"<=2) |
| 7 - filter(ROW_NUMBER() OVER ( ORDER BY NULL)<=2) |
| 10 - filter("ID" IS NOT NULL) |
| |
db<>fiddle here
I want to join two tables, where the first table has more entries than the second, such that rows from each are joined in order. Maybe a little example would be helpful:
Table T:
| tid | sid | ron | val | seqno |
| --- | --- | --- | --- | --- |
| 1 | a | x1 | 15 | 1 |
| 2 | b | x2 | 10 | 3 |
| 2 | b | x3 | 20 | 4 |
| 3 | a | x5 | 10 | 5 |
| 4 | c | x9 | 15 | 7 |
| 4 | c | x9 | 15 | 8 |
| 4 | c | x9 | 20 | 10 |
| 4 | c | x9 | 15 | 11 |
| 6 | b | x11 | 22 | 12 |
| 7 | b | x12 | 10 | 14 |
| 7 | b | x13 | 10 | 16 |
| 7 | b | x13 | 10 | 17 |
| 7 | b | x14 | 10 | 19 |
The second table (Table C) is as follows (in reality, more columns):
| tid | sid | ron | val | fid |
| --- | --- | --- | --- | --- |
| 2 | b | x3 | 20 | 54 |
| 4 | c | x9 | 15 | 12 |
| 4 | c | x9 | 15 | 14 |
| 4 | c | x9 | 20 | 15 |
| 4 | c | x9 | 15 | 20 |
| 7 | b | x13 | 10 | 112 |
| 7 | b | x13 | 10 | 113 |
seqNo and fid are there in each table to provide ordering within the groups formed by (tid, sid, ron), and that is the ordering I'd like to maintain.
How can I get from these two tables to something like the following table?
| tid | sid | ron | val | fid | seqno |
| --- | --- | --- | --- | --- | --- |
| 2 | b | x3 | 20 | 54 | 4 |
| 4 | c | x9 | 15 | 12 | 7 |
| 4 | c | x9 | 15 | 14 | 8 |
| 4 | c | x9 | 20 | 15 | 10 |
| 4 | c | x9 | 15 | 20 | 11 |
| 7 | b | x13 | 10 | 112 | 16 |
| 7 | b | x13 | 10 | 113 | 17 |
I can't assign a rank to each element in the group and use that for matching inside of a LEFT JOIN, since there are cases where matching doesn't begin at the end of the group (for example tid=7). Also, because val in the same group may have repeated values, I can't blindly match on it either, as that may blow up the number of rows.
This is what I managed to get late last night, seems to be working correctly:
WITH
table_t AS (
SELECT *
FROM (VALUES
(1,'a','x1',15,1),
(2,'b','x2',10,3),
(2,'b','x3',20,4),
(3,'a','x5',10,5),
(4,'c','x9',15,7),
(4,'c','x9',15,8),
(4,'c','x9',20,10),
(4,'c','x9',15,11),
(6,'b','x11',22,12),
(7,'b','x12',10,14),
(7,'b','x13',10,16),
(7,'b','x13',10,17),
(7,'b','x14',10,19)
) AS c(tid, sid, ron, val, seq)
),
table_t_ranked AS (
SELECT *
, DENSE_RANK() OVER (PARTITION BY tid, sid, ron ORDER BY seq ASC) AS ranking
FROM table_t
),
table_c AS (
SELECT *
FROM (VALUES
(2,'b','x3',20,54),
(4,'c','x9',15,12),
(4,'c','x9',15,14),
(4,'c','x9',20,15),
(4,'c','x9',15,20),
(7,'b','x13',10,112),
(7,'b','x13',10,113)
) AS c(tid, sid, ron, val, fid)
),
table_c_ranked AS (
SELECT *
, DENSE_RANK() OVER (PARTITION BY tid, sid, ron ORDER BY fid ASC) AS ranking
FROM table_c
),
foo AS (
SELECT c.*
, t.seq
, t.ranking as ranking_t
FROM table_c_ranked c
LEFT JOIN table_t_ranked t
ON c.tid = t.tid
AND c.sid = t.sid
AND c.ron = t.ron
AND c.val = t.val
)
SELECT tid, sid, ron, val, fid, seq
FROM foo
WHERE ranking = ranking_t
ORDER BY tid, seq
I'm struggling a hierarchical SQL query. I want to have another 2 columns of the disp_order of its children and sibling.
Children - Should hold all disp_order of their child and their grand children and so far.
Sibling - Should hold the disp_order of the row having the same parent.
+------------+-----+-------------+--------+
| disp_order | lvl | description | parent |
+------------+-----+-------------+--------+
| 0 | 1 | A | |
| 1 | 2 | B | 0 |
| 2 | 3 | C | 1 |
| 3 | 4 | D | 2 |
| 4 | 5 | E | 3 |
| 5 | 2 | F | 0 |
| 6 | 3 | G | 5 |
| 7 | 3 | H | 5 |
| 8 | 3 | I | 5 |
| 9 | 4 | J | 8 |
| 10 | 5 | K | 9 |
+------------+-----+-------------+--------+
What the result should be:
+------------+-----+-------------+--------+------------------------+---------+
| disp_order | lvl | description | parent | children | sibling |
+------------+-----+-------------+--------+------------------------+---------+
| 0 | 1 | A | | 1,2,3,4,5,6,7,8,9,10 | |
| 1 | 2 | B | 0 | 2,3,4 | 5 |
| 2 | 3 | C | 1 | 3,4 | |
| 3 | 4 | D | 2 | 4 | |
| 4 | 5 | E | 3 | | |
| 5 | 2 | F | 0 | 6,7,8,9,10 | 1 |
| 6 | 3 | G | 5 | | 7,8 |
| 7 | 3 | H | 5 | | 6,8 |
| 8 | 3 | I | 5 | 9,10 | 6,7 |
| 9 | 4 | J | 8 | 10 | |
| 10 | 5 | K | 9 | | |
+------------+-----+-------------+--------+------------------------+---------+
Here is my current query:
SELECT t.*,
( SELECT MAX( disp_order )
FROM tbl_pattern p
WHERE p.lvl = t.lvl - 1
AND p.disp_order < t.disp_order ) AS parent
FROM tbl_pattern t
Continuing from your previous question:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE tbl_pattern ( order_no, code, disp_order, lvl, description ) AS
SELECT 'RM001-01', 1, 0, 1, 'HK140904-1A' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 1, 2, 'HK140904-1B' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 2, 3, 'HK140904-1B' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 3, 4, 'HK140904-1C' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 4, 5, 'HK140904-1D' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 5, 2, 'HK140904-1E' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 6, 3, 'HK140904-1E' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 7, 3, 'HK140904-1X' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 8, 4, 'HK140904-1E' FROM DUAL UNION ALL
SELECT 'RM001-01', 1, 9, 5, 'HK140904-1E' FROM DUAL;
Query 1:
WITH data ( order_no, code, disp_order, lvl, description, parent ) AS (
SELECT t.*,
( SELECT MAX( disp_order )
FROM tbl_pattern p
WHERE p.order_no = t.order_no
AND p.code = t.code
AND p.lvl = t.lvl - 1
AND p.disp_order < t.disp_order ) AS parent
FROM tbl_pattern t
)
SELECT d.*,
( SELECT LISTAGG( c.disp_order, ',' ) WITHIN GROUP ( ORDER BY c.disp_order )
FROM data c
START WITH c.parent = d.disp_order
AND c.order_no = d.order_no
AND c.code = d.code
CONNECT BY PRIOR c.disp_order = c.parent
AND PRIOR c.order_no = c.order_no
AND PRIOR c.code = c.code
) AS children,
( SELECT LISTAGG( c.disp_order, ',' ) WITHIN GROUP ( ORDER BY c.disp_order )
FROM data c
WHERE c.parent = d.parent
AND c.disp_order <> d.disp_order
AND c.order_no = d.order_no
AND c.code = d.code
) AS siblings
FROM data d
Results:
| ORDER_NO | CODE | DISP_ORDER | LVL | DESCRIPTION | PARENT | CHILDREN | SIBLINGS |
|----------|------|------------|-----|-------------|--------|-------------------|----------|
| RM001-01 | 1 | 0 | 1 | HK140904-1A | (null) | 1,2,3,4,5,6,7,8,9 | (null) |
| RM001-01 | 1 | 1 | 2 | HK140904-1B | 0 | 2,3,4 | 5 |
| RM001-01 | 1 | 2 | 3 | HK140904-1B | 1 | 3,4 | (null) |
| RM001-01 | 1 | 3 | 4 | HK140904-1C | 2 | 4 | (null) |
| RM001-01 | 1 | 4 | 5 | HK140904-1D | 3 | (null) | (null) |
| RM001-01 | 1 | 5 | 2 | HK140904-1E | 0 | 6,7,8,9 | 1 |
| RM001-01 | 1 | 6 | 3 | HK140904-1E | 5 | (null) | 7 |
| RM001-01 | 1 | 7 | 3 | HK140904-1X | 5 | 8,9 | 6 |
| RM001-01 | 1 | 8 | 4 | HK140904-1E | 7 | 9 | (null) |
| RM001-01 | 1 | 9 | 5 | HK140904-1E | 8 | (null) | (null) |
I have 3 tables:
+-----+---------+
|cl_id| name |
+-----+---------+
| 1 | adaf |
| 2 | rich | - clients
| 3 | call |
| 4 | alen |
| 5 | courney |
| 6 | warren |
+-----+---------+
+-----+---------+
|cl_id| data |
+-----+---------+
| 1 | 13 |
| 2 | 1000 | - table1
| 5 | 0 |
| 6 | 0 |
+-----+---------+
+-----+---------+
|cl_id| data |
+-----+---------+
| 2 | -355 | - table2
| 3 | 35 |
| 3 | 10 |
| 5 | 46 |
| 5 | 50 |
| 5 | 10 |
+-----+---------+
And I have to combine those three tables, so the result should be:
+-----+---------+--------+---------+
|cl_id| name |data_tb1|data_tb2 |
+-----+---------+--------+---------+
| 1 | adaf | 13 | 0 |
| 2 | rich | 1000 | -355 |
| 3 | call | 0 | 45 |
| 4 | alen | 0 | 0 |
| 5 | courney| 0 | 106 |
| 6 | warren | 0 | 0 |
+-----+---------+--------+---------+
It should output all clients and theirs SUM(data) from table1 and table2. clients goes one-to-more.
Thanks in advance
Simply using LEFT JOIN and GROUP BY
SELECT c.cl_id,
c.name,
COALESCE(SUM(t1.data), 0) AS data_tb1,
COALESCE(SUM(t2.data), 0) AS data_tb2
FROM clients c
LEFT JOIN table1 t1 ON c.cl_id = t1.cl_id
LEFT JOIN table2 t2 ON c.cl_id = t2.cl_id
GROUP BY c.cl_id,
c.name
ORDER BY c.cl_id;
If you are using SQL Server then simple Use Left Join as below :
SELECT C.cl_id,
C.name,
SUM(ISNULL(T.data, 0)) data_tb1,
SUM(ISNULL(T1.data, 0)) data_tb2
FROM
(
SELECT *
FROM clients
) C
LEFT JOIN table1 T ON T.cl_id = C.cl_id
LEFT JOIN table2 T1 ON T1.cl_id = C.cl_id
GROUP BY C.cl_id,
C.name
ORDER BY C.cl_id;
Desired Output :
+-----+---------+--------+---------+
|cl_id| name |data_tb1|data_tb2 |
+-----+---------+--------+---------+
| 1 | adaf | 13 | 0 |
| 2 | rich | 1000 | -355 |
| 3 | call | 0 | 45 |
| 4 | alen | 0 | 0 |
| 5 | courney| 0 | 106 |
| 6 | warren | 0 | 0 |
+-----+---------+--------+---------+