hierarchical query without side rows - sql

I have "id-parent_id related" data, like this:
1
/ \
/ \
2 4
/
/
3
I have the code, that returns data for all rows related to particular (related to condition in the start with clause) tree - in both sides ("up" and "down"), for example:
with
temp_cte(id, parent_id) as
(select 1, null from dual
union all
select 2, 1 from dual
union all
select 3, 2 from dual
union all
select 4, 1 from dual
union all
select 5, null from dual)
select *
from temp_cte t
connect by nocycle (prior id = parent_id) or (prior parent_id = id)
start with t.id = 2
order by id
How do i get data without "side" ("right"/"left") rows?
e.g. for the drawn above -
I need data without 4 when I start with 2 or 3,
and I need data without 2 and 3 when I start with 4
(if start with 1, I still want the full tree)

This is because of OR predicate in CONNECT BY: your query traverses in both directions, so on the second step of CONNECT BY you'll have all the childs of the parent and finally all the tree.
You need to split the query into union of two directions.
with
temp_cte(id, parent_id) as
(select 1, null from dual
union all
select 2, 1 from dual
union all
select 3, 2 from dual
union all
select 4, 1 from dual
union all
select 5, null from dual
)
select id, parent_id
from temp_cte t
where level > 1
connect by nocycle (prior id = parent_id)
start with t.id = 2
union all
select id, parent_id
from temp_cte t
connect by (prior parent_id = id)
start with t.id = 2
order by id
ID | PARENT_ID
-: | --------:
1 | null
2 | 1
3 | 2
db<>fiddle here

Related

Select parent of parent when is not null in oracle

I have these rows in the specific parent child table:
Id - parentId
1 - null
2 - null
3 - 2
4 - 2
5 - 4
6 - 1
Indeed for example i want to enter 3 and get 2, enter 5 and get 2, and enter 6 and get 1, how can i do that?
You need a hierarchical query (connect by ...) Something like this:
with
tbl (id, parentid) as (
select 1, null from dual union all
select 2, null from dual union all
select 3, 2 from dual union all
select 4, 2 from dual union all
select 5, 4 from dual union all
select 6, 1 from dual
)
select id
from tbl
where connect_by_isleaf = 1
start with id = 5
connect by id = prior parentid
;
ID
-----
2
"In real life" you would have a table tbl with columns id and parentid (I simulated that in the with clause, but that is just for convenience; remove it first.) And you wouldn't hard-code the starting node; you would likely use a bind variable in the start with clause.
The key here is the where clause, using the connect_by_isleaf pseudocolumn.

How can I get all the parent element by providing child element ID in oracle?

My Oracle table looks like this
ID | ParentID
-----------------
1 | 0
2 | 1
3 | 2
4 | 3
5 | 3
If I know only ID and need to get all parent elements in oracle, what is the query I need to use?
ex:- If I pass 5, need to get 5 > 3 > 2 > 1
For example:
SQL> with test (id, parent) as
2 (select 1, 0 from dual union
3 select 2, 1 from dual union
4 select 3, 2 from dual union
5 select 4, 3 from dual union
6 select 5, 3 from dual
7 )
8 select listagg(id, '->') within group (order by level) result
9 from test
10 start with id = &par_id
11 connect by prior parent = id;
Enter value for par_id: 5
RESULT
---------------------------------------------------------------------
5->3->2->1
SQL>
You may use a recursive CTE
WITH cte (id, parentid, p)
AS (SELECT id,
parentid,
To_char(id) AS p
FROM t
WHERE id = :p_id --enter 5
UNION ALL
SELECT t.id,
t.parentid,
c.p
|| '>'
|| t.id AS p
FROM t
JOIN cte c
ON ( c.parentid = t.id ))
SELECT p
FROM cte
WHERE parentid = 0 --Highest parent.
Demo

Connect by prior get parents and children

I'm working on a query which use connect by prior.
I have written a query which retrieves all children of an entity. What I want is to retrieve both children and parents rows.
Here is my SQL :
Select *
From myTable tab
Connect By Prior tab.id= tab.child_id
Start With tab.id= 2;
How could I retrieve parents ?
Thanks.
Use UNION ALL to combine a query to get the children with another to get the ancestors.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE myTable ( id, child_id ) AS
SELECT 0, 1 FROM DUAL UNION ALL
SELECT 1, 2 FROM DUAL UNION ALL
SELECT 2, 3 FROM DUAL UNION ALL
SELECT 3, 4 FROM DUAL UNION ALL
SELECT 4, 5 FROM DUAL UNION ALL
SELECT 3, 6 FROM DUAL UNION ALL
SELECT 0, 7 FROM DUAL UNION ALL
SELECT 1, 8 FROM DUAL;
Query 1:
SELECT * -- Child Rows
FROM mytable
START WITH id = 2
CONNECT BY PRIOR child_id = id
UNION ALL
SELECT * -- Ancestor Rows
FROM mytable
START WITH child_id = 2
CONNECT BY PRIOR id = child_id
Results:
| ID | CHILD_ID |
|----|----------|
| 2 | 3 |
| 3 | 4 |
| 4 | 5 |
| 3 | 6 |
| 1 | 2 |
| 0 | 1 |
An alternative approach to a hierarchical query, if you're on 11gR2 or higher, is recursive subquery factoring:
with rcte (id, child_id, some_other_col) as (
select id, child_id, some_other_col -- whichever columns you're interested in
from myTable
where id = 2
union all
select t.id, t.child_id, t.some_other_col -- whichever columns you're interested in
from rcte r
join myTable t
on t.id = r.child_id -- match parents
or t.child_id = r.id -- match children
)
cycle id set is_cycle to 1 default 0
select id, child_id, some_other_col -- whichever columns you're interested in
from rcte
where is_cycle = 0;
The anchor member finds your initial target row. The recursive member then looks for parents or children of each row found so far.
The final query can get whichever columns you want, do aggregation, etc.
(Possibly worth testing both approaches with real data to see if there is a performance difference, of course).

Oracle SQL: Find root parent for hierarchical data with child_id (No parent_id)

Say I have table A:
id child_id
1 2
2 3
3 NULL
4 NULL
5 6
6 7
7 8
8 NULL
I need a query to get root parent id of each row, this output for example:
id root_parent_id
1 1
2 1
3 1
4 4
5 5
6 5
7 5
8 5
I've tried both CONNECT BY and CTE by examples, but seems all I found based on rows with parent_id and not child_id and doesn't work.
CONNECT BY query I tried:
SELECT id, child_id, LEVEL, connect_by_root id
FROM a
CONNECT BY id = PRIOR child_id
CTE query I tried:
WITH recursion_view (base,
id,
child_id)
AS (
SELECT id base, id, child_id FROM a
UNION ALL
SELECT
previous_level.base,
current_level.id,
current_level.child_id
FROM recursion_view previous_level, a current_level
WHERE current_level.id = previous_level.child_id)
SELECT base,
id,
child_id
FROM recursion_view
ORDER BY base, id, child_id
You need to traverse the hierarchy in reverse order - view the root parents as leaves. Something like this:
with table_a ( id, child_id ) as (
select 1, 2 from dual union all
select 2, 3 from dual union all
select 3, NULL from dual union all
select 4, NULL from dual union all
select 5, 6 from dual union all
select 6, 7 from dual union all
select 7, 8 from dual union all
select 8, NULL from dual
)
select connect_by_root id as id, id as root_parent_id
from table_a
where connect_by_isleaf = 1
connect by child_id = prior id
order by id
;
ID ROOT_PARENT_ID
-- --------------
1 1
2 1
3 1
4 4
5 5
6 5
7 5
8 5

how to find the last level child nodes in tree kind structure in database using SQL

I have a parent child relationship stored in a table
If I query with 1, I want to retrieve all the LAST LEVEL Children of 1.
I should get back 5, 6,8.
Ignore any cyclical data that comes along.
Please see the attached image
Use a hierarchical query and restrict the output to only the non-cyclic leaf rows using the pseudocolumns CONNECT_BY_ISLEAF and CONNECT_BY_ISCYCLE:
Oracle Setup:
CREATE TABLE your_table ( parent_column, child_column ) AS
SELECT 1, 2 FROM DUAL UNION ALL
SELECT 2, 3 FROM DUAL UNION ALL
SELECT 3, 4 FROM DUAL UNION ALL
SELECT 4, 5 FROM DUAL UNION ALL
SELECT 3, 6 FROM DUAL UNION ALL
SELECT 3, 7 FROM DUAL UNION ALL
SELECT 7, 8 FROM DUAL;
Query:
SELECT child_column
FROM your_table
WHERE CONNECT_BY_ISLEAF = 1
AND CONNECT_BY_ISCYCLE = 0
START WITH parent_column = 1
CONNECT BY NOCYCLE PRIOR child_column = parent_column
Output:
CHILD_COLUMN
------------
5
6
8