SQL get all children - sql

So I have hierarchical data that is organized in departments, with each department having a parent department except for the top one. I now want to write a SELECT statement to select this hierarchical structure in a cumulative way. That means that for every level in the hierarchy I want to see all the entries that are children of that.
For example, if I have the following tables:
Departments
ID PARENT_ID
1 null
2 1
3 1
4 2
5 2
6 3
7 3
Employees
ID DEPT
1 2
2 2
3 3
4 4
5 5
6 6
7 7
8 2
9 3
10 4
11 5
12 6
13 7
14 2
15 3
16 4
17 5
I would like to have something like the following result:
ID_E ROOT DEPT
1 null 1
1 1 2
2 null 1
2 1 2
3 null 1
3 1 3
4 null 1
4 1 2
4 2 4
5 null 1
...
I have looked around and fiddled a bit but just cannot get it to work.
I thought this would do the trick but it gives weird results (meaning many duplicate rows):
SELECT connect_by_root(dept.id) AS dept_id,
CONNECT_BY_ROOT(dept.parent_id) AS parent_id,
emp.id AS id_e
FROM emp
RIGHT JOIN dept ON emp.dept = dept.id
CONNECT BY PRIOR dept.id = dept.parent_id
EDIT: Here is a fiddle of the scenario

I came up with a solution, using a recursive CTE to parse the hierarchy and retrieve each possible way a department can connect to the root, which is then joined with the employee table.
Could you give it a try, and let me know if it works?
WITH RCTE_DEPT(id,root,parent_id) AS(
SELECT id,parent_id, id
FROM dept
UNION ALL
SELECT dept.id,root,RCTE_DEPT.parent_id
FROM dept
JOIN RCTE_DEPT ON
dept.parent_ID = RCTE_DEPT.id)
SELECT emp.id as ID_E, RCTE_DEPT.root as ROOT, RCTE_DEPT.parent_id as DEPT
FROM emp
JOIN RCTE_DEPT ON emp.DEPT = RCTE_DEPT.id
ORDER BY ID_E ASC, ROOT ASC, DEPT ASC
Here is a fiddle.

Related

Get max record for each group of records, link multiple tables

I seek to find the maximum timestamp (ob.create_ts) for each group of marketid's (ob.marketid), joining tables obe (ob.orderbookid = obe.orderbookid) and market (ob.marketid = m.marketid). Although there are a number of solutions posted like this for a single table, when I join multiple tables, I get redundant results. Sample table and desired results below:
table: ob
orderbookid
marketid
create_ts
1
1
1664635255298
2
1
1664635255299
3
1
1664635255300
4
2
1664635255301
5
2
1664635255302
6
2
1664635255303
table: obe
orderbookentryid
orderbookid
entryname
1
1
'entry-1'
2
1
'entry-2'
3
1
'entry-3'
4
2
'entry-4'
5
2
'entry-5'
6
3
'entry-6'
7
3
'entry-7'
8
4
'entry-8'
9
5
'entry-9'
10
6
'entry-10'
table: m
marketid
marketname
1
'market-1'
2
'market-2'
desired results
ob.orderbookid
ob.marketid
obe.orderbookentryid
obe.entryname
m.marketname
3
1
6
'entry-6'
'market-1'
3
1
7
'entry-7'
'market-1'
6
2
10
'entry-10'
'market-2'
Use ROW_NUMBER() to get a properly filtered ob table. Then JOIN the other tables onto that!
WITH
ob_filtered AS (
SELECT
orderbookid,
marketid
FROM
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY
marketid
ORDER BY
create_ts DESC
) AS create_ts_rownumber
FROM
ob
) ob_with_rownumber
WHERE
create_ts_rownumber = 1
)
SELECT
ob_filtered.orderbookid,
ob_filtered.marketid,
obe.orderbookentryid,
obe.entryname,
m.marketname
FROM
ob_filtered
JOIN m
ON m.marketid = ob_filtered.marketid
JOIN obe
ON ob_filtered.orderbookid = obe.orderbookid
;

Make a query to display unmatched data

I m having difficulty making a query that displays unmatched data in between 2 tables.
The tables are:
Employee data Salary data
ID Holidays ID Holiday
1 10 0 10
2 8 1 5
3 5 2 8
4 7 3 5
5 8 7 6
6 5 8 9
7 6 9 2
8 9 10 3
the primary key is ID for both tables.
I want my query result to contain all the values that does not match in both tables.
The type of output i want is something like this:
ID Holiday
0 10
1 10
1 5
4 7
5 8
6 5
9 2
10 3
I tried using unmatched query wizard but that only compares ID, not the Holiday column.
Please help me!
You could use a union of two exists queries:
SELECT ID, Holiday FROM Employee as e
WHERE NOT EXISTS (SELECT 1 FROM Salary as s WHERE s.ID = e.ID AND s.Holiday = e.Holiday)
UNION ALL
SELECT ID, Holiday FROM Salary as s
WHERE NOT EXISTS (SELECT 1 FROM Employee as e WHERE e.ID = s.ID AND e.Holiday = s.Holiday);

Get all of child nodes in a hierarchical data in 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

T-SQL get all nodes and their last level children using common table expression

I need the last level children of all nodes between the last level and the parent. I am new to recursive ctes and trying to get this result.
Consider the following table:
emp id | mgr id
1 null
2 1
3 1
4 1
5 2
6 2
7 3
8 3
9 4
10 4
11 5
12 6
13 6
14 6
15 11
if the input is (15) then the output should be
mgr id emp id
2 12
2 13
2 14
2 15
5 15
6 12
6 13
6 14
11 15
Searching around the web I figured this can be done using recursive queries but I am unable to.
with cte as
(
select
emp_id, mgr_id
from
emp_heirarchy
where
emp_id in (select MIN(lt.emp_id)
from landing_table lt
inner join emp_heirarchy eh on lt.emp_id = eh.emp_id
group by mgr_id)
union all
select
eh.emp_id, eh.mgr_id
from
emp_heirarchy eh
inner join
cte c on c.mgr_id = eh.emp_id
)
select distinct *
from cte
order by mgr_id
I have tried a few other versions of the above query with no luck.

CTE to Group Employees that are in different departments Many to Many

Can anyone help please! I just cant seem to solve this puzzle?
Input Table
DepartmentID EmpID
-----------------------
1 100
1 101
1 103
1 200
2 300
2 350
3 350
3 100
4 50
4 30
4 45
5 50
5 51
5 52
5 53
6 53
6 54
7 54
7 55
8 55
8 56
10 800
11 900
Output Table
Please note that GroupID is created by us to group departments that have common employees, with the condition that 1 employee cannot be in two departments.
GroupID Department
-----------------------
1000 1
1000 2
1000 3
1001 4
1001 5
1001 6
1001 7
1001 8
1002 10
1003 11
Example to show how and why Department 1, 2 & 3 are grouped:
EmpID 100 is common between Department 1 & 3, but wait! EmpID 350 is common between 2 & 3 as well. So group them as well. Now the Group created by departments 1, 2 and 3 do not any product that is in any other department, then we can stop.
Note: This is not a 'normal' group by because we dont want any 2 groups that we create to have same employee.
LOGIC:
Step1: EmpID 50 is common between department 4 & 5. So Group 4 & 5 together
Step2: So this means Group of 4 & 5 have 50,30,45,51,52,53 unique employees
Step3: But wait! the Department 6 has EmpID 53 common with the Group of 4 & 5, formed in step2
Step4: Group department 4, 5, and 6. This new group has unique employees of 50,30,45,51,52,53,54
Step5: But wait! the department 7 has EmpID of 54, which is common with the Group formed in step4. So Group them together
This goes on.... Till we don`t have any employee that is not in 2 groups. So in this case Group 7, Group 8 will also need to be 'merged' into the Group that is mentioned in Step 4.
This is a graph traversal problem that requires recursive CTEs. I think this is one approach:
with cte as (
select department, empid
from inputs
union all
select cte.department, i.empid
from inputs i join
cte
on i.empid = cte.empid and i.department <> cte.department
)
select department,
row_number() over (order by min(empid)) as groupid
from cte
group by deparment;