Get all of child nodes in a hierarchical data in SQL - sql

I have the following sql table:
id parent_id
1 null
2 1
3 4
4 8
5 1
6 2
7 6
8 null
How can i get all of child nodes of some specific node?
For example with id = 1:
1 2 5 6 7
with id = 8
8 4 2

I've figured out in another blog, hope it will help other people:
with RECURSIVE cte(id,parent_id) as (
select
id,
parent_id
from forum
where id = 2
UNION ALL
select
forum.id,
forum.parent_id
from forum
inner join cte on forum.parent_id = cte.id
)
select * from cte

Related

How to select parent child till end using root parent id in sql?

Below the table :
I need to get without recursion, but use any other join and union.
Id ParentId
1 0
2 1
3 2
4 2
5 4
6 5
7 6
8 7
9 8
N N
Without recursion use any other join queries
DECLARE #Nvalue INT = 10
SELECT NUMBER AS ID,NUMBER-1 AS ParentID FROM (
SELECT DISTINCT NUMBER FROM master..spt_values WHERE number BETWEEN 1 AND #Nvalue
)T

Updating column based on another column's value

How do i update table structured like this:
id[pkey] | parent_id | position
1 1
2 1
3 1
4 1
5 1
6 2
7 2
8 2
9 2
10 3
11 3
12 3
...and so on
to achieve this result:
id[pkey] | parent_id | position
1 1 1
2 1 2
3 1 3
4 1 4
5 1 5
6 2 1
7 2 2
8 2 3
9 2 4
10 3 1
11 3 2
12 3 3
...and so on
I was thinking about somehow mixing
SELECT DISTINCT parent_id FROM cats AS t;
with
CREATE SEQUENCE dpos;
UPDATE cats t1 SET position = nextval('dpos') WHERE t.parent_id = t1.parent_id;
DROP SEQUENCE dpos;
although im not really experienced with postgres, and not sure how to use some kind of FOREACH. I appreciate any help
You can get the incremental number using row_number(). The question is how to assign it to a particular row. Here is one method using a join:
update cats
set position = c2.newpos
from (select c2.*, c2.ctid as c_ctid,
row_number() over (partition by c2.parent_id order by NULL) as seqnum
from cats c2
) c2
where cats.parent_id = c2.parent_id and cats.ctid = c2.c_ctid;
Use row_number function
select parent_id,
row_number() over (partition by parent_id order by parent_id) as position_id from table
Try this:
UPDATE table_name set table_name.dataID = v_table_name.rn
FROM
(
SELECT row_number() over (partition by your_primaryKey order by your_primaryKey) AS rn, id
FROM table_name
) AS v_table_name
WHERE v_table_name.your_primaryKey = v_table_name.your_primaryKey;

Oracle , select relation

I have 2 tables in oracle DB: Items and Relationship.
items:
ID
---
1
2
3
4
5
6
7
relationship:
ID parent child
--------------------
1 1 2
2 1 3
3 1 4
4 2 5
5 2 6
6 3 7
In the relationship table, I'm storing the hierarchial structure of the "items" (do not ask why it's stored in different tables).
The question:
When I execute this query:
SELECT PARENT_ID, CHILD_ID, CONNECT_BY_ISLEAF, MAX(LEVEL) OVER () + 1 - LEVEL as rev_level
FROM relationship
CONNECT BY PRIOR PARENT_ID = CHILD_ID
START WITH CHILD_ID = 7;
I do not see the root parent because he doesn't exist in this table as a child.
The question is how can I add the root parent(ID = 1) to the query result or join it whith the "items" table and keep the result columns (level and isleaf).
CONNECT_BY_ISLEAF works the other way around when using bottom up search (see this link http://technology.amis.nl/2009/11/14/oracle-11gr2-alternative-for-connect_by_isleaf-function-for-recursive-subquery-factoring-dedicated-to-anton/)
I assume that you want to show more data about the item (like name) If that is the case just left join the items table.
SELECT PARENT_ID AS PARENT_ID,CHILD_ID, i.name AS CHILD_NAME,
CONNECT_BY_ISLEAF,
MAX(LEVEL) OVER () + 1 - LEVEL AS rev_level
FROM items i
LEFT JOIN relationship r ON (i.id = r.CHILD_ID)
CONNECT BY PRIOR PARENT_ID = CHILD_ID
START WITH CHILD_ID = 7
ORDER BY REV_LEVEL;
check this SQLfiddle: http://sqlfiddle.com/#!4/5c9fa/17
In addition check this post about bottom up searches (http://bitbach.wordpress.com/2010/10/18/implementing-bottom-up-path-traversal-for-hierarchical-tables/)
Notice that you have both directions - parent and child.
pick one and dont mix the two.
1 with x as (
2 select 1 as id, 1 as parent, 2 as child from dual union all
3 select 2, 1 , 3 from dual union all
4 select 3 ,1, 4 from dual union all
5 select 4 ,2, 5 from dual union all
6 select 5 ,2, 6 from dual union all
7 select 6 ,3, 7 from dual)
8 select *
9 from x
10 sTART WITH child = 7
11* CONNECT BY PRIOR id= CHILD
SQL> /
ID PARENT CHILD
---------- ---------- ----------
6 3 7
5 2 6
4 2 5
3 1 4
2 1 3
1 1 2
connection is made by prior id = child and not prior parent = child

Parent child hierarchy in sql server

I have the following requirement,
Input
CID ParentID
1 10
2 1
3 1
4 2
5 2
6 2
7 2
8 4
9 4
10 NULL
20 25
30 38
15 51
17 71
when I pass child value as 4 following is my desired output:
Desired Output:
CID ParentID
2 4
1 2
10 1
NULL 10
4 2
4 8
2 4
2 5
2 6
1 3
2 7
    
Please help! Thanks in advance.
Your explanation and your data don't match. I think the row (4, 2) in the results should be (4,9). If I'm correct, then this should do what you want:
with Parents(lvl, CID, ParentID) as (
select 0, ParentID, CID
from T
where CID = 4
union all
select lvl+1, T.ParentID, T.CID
from T join Parents
on T.CID = Parents.CID
)
select CID, ParentID
from Parents
union all
select T.ParentID, T.CID
from T join Parents
on Parents.ParentID = T.ParentID;
SQL fiddle here.

SQL: Hierarchical query with multiple roots / parents

I have a table describing elements organized in a tree-like structure:
ID, PARENT_ID, NAME
0 null TOP
1 0 A
2 0 B
3 0 C
4 1 AA
5 2 BA
6 3 CA
7 6 CAA
...
There can be many levels in this hierarchy.
Suppose there is a list of elements (say IDs 2 and 3) for which I would like to get all child records from the table.
Something like this:
select *
from MY_TABLE
start with PARENT_ID in (2,3)
connect by PARENT_ID = prior ID
will return:
ID, PARENT_ID, NAME
5 2 BA
6 3 CA
7 6 CAA
However, I want the each output record to be mapped to the original parent from my list (2,3) so that the output would look like this:
ORIGINAL_PARENT_ID, ID, PARENT_ID, NAME
2 5 2 BA
3 6 3 CA
3 7 6 CAA
How can it be done?
connect_by_root may be what you're after?
SQL> select t.*, connect_by_root parent_id as ORIGINAL_PARENT_ID
2 from MY_TABLE t
3 start with PARENT_ID in (2,3)
4 connect by PARENT_ID = prior ID
5 /
ID PARENT_ID NAM ORIGINAL_PARENT_ID
---------- ---------- --- ------------------
5 2 BA 2
6 3 CA 3
7 6 CAA 3
Assuming your names are really as you have them, then the problem can be done without connect by. You can use simple string manipulation.
with ToFind (
select 'C' as parent from dual union all
select 'B' as parent from dual
)
select t.*
from t join
ToFind tf
on t.name like tf.parent, 100)||'%' and t.name <> tf.parent