Simplest way to do a recursive self-join?
WITH q AS
(
SELECT *
FROM mytable
WHERE ParentID IS NULL -- this condition defines the ultimate ancestors in your chain, change it as appropriate
UNION ALL
SELECT m.*
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
By adding the ordering condition, you can preserve the tree order:
WITH q AS
(
SELECT m.*, CAST(ROW_NUMBER() OVER (ORDER BY m.PersonId) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN AS bc
FROM mytable m
WHERE ParentID IS NULL
UNION ALL
SELECT m.*, q.bc + '.' + CAST(ROW_NUMBER() OVER (PARTITION BY m.ParentID ORDER BY m.PersonID) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
ORDER BY
bc
By changing the ORDER BY
condition you can change the ordering of the siblings.
SQL Server recursive self join
Recursive cte to the rescue....
Create and populate sample table (Please save us this step in your future questions):
DECLARE @T as table
(
id int,
name varchar(100),
parent_id int
)
INSERT INTO @T VALUES
(1, 'A', NULL),
(2, 'A.1', 1),
(3, 'A.2', 1),
(4, 'A.1.1', 2),
(5, 'B', NULL),
(6, 'B.1', 5),
(7, 'B.1.1', 6),
(8, 'B.2', 5),
(9, 'A.1.1.1', 4),
(10, 'A.1.1.2', 4)
The cte:
;WITH CTE AS
(
SELECT id, name, name as path, parent_id
FROM @T
WHERE parent_id IS NULL
UNION ALL
SELECT t.id, t.name, cast(cte.path +','+ t.name as varchar(100)), t.parent_id
FROM @T t
INNER JOIN CTE ON t.parent_id = CTE.id
)
The query:
SELECT id, name, path
FROM CTE
Results:
id name path
1 A A
5 B B
6 B.1 B,B.1
8 B.2 B,B.2
7 B.1.1 B,B.1,B.1.1
2 A.1 A,A.1
3 A.2 A,A.2
4 A.1.1 A,A.1,A.1.1
9 A.1.1.1 A,A.1,A.1.1,A.1.1.1
10 A.1.1.2 A,A.1,A.1.1,A.1.1.2
See online demo on rextester
How to self JOIN recursively in SQL?
If you are using SQL Server 2005+, you can use common-table expressions
With Family As
(
Select s.ID, s.ParentSeriesId, 0 as Depth
From Series s
Where ID = @ParentID
Union All
Select s2.ID, s2.ParentSeriesId, Depth + 1
From Series s2
Join Family
On Family.ID = s2.ParentSeriesId
)
Select *
From Family
For more:
Recursive Queries Using Common Table Expressions
What is the best way to do a recursive SQL query on a self join field (as well as doing it through nhibernate?)
Using a recursive CTE, you can build the hierarchy. Filtering the top level query by your search criteria, you can get the results you're looking for.
DECLARE @id INT;
SET @id = 3;
WITH Emp
AS (SELECT te.id
, te.Name
, te.ManagerId
, CAST(NULL AS VARCHAR(10)) AS ManagerName
FROM dbo.tblEmployee AS te
-- Get entire heirarchy with the NULL ManagerId
--WHERE ManagerId IS NULL
WHERE te.id = @id
UNION ALL
SELECT te2.id
, te2.Name
, e.id
, e.Name
FROM dbo.tblEmployee AS te2
JOIN Emp e
ON e.id = te2.ManagerId
)
SELECT *
FROM Emp;
UPDATE:
For your comment about not including the record for the id
passed, you can do two things:
The easiest way would be to add a where clause to the last select:
SELECT *
FROM Emp
WHERE emp.ID <> @id;
Alternatively, if you didn't need the ManagerName
field to be populated for the top level of the hierarchy, you can what the first where clause in the CTE:
SELECT te.id
, te.Name
, te.ManagerId
, CAST(NULL AS VARCHAR(10)) AS ManagerName
FROM dbo.tblEmployee AS te
-- Get entire heirarchy with the NULL ManagerId
--WHERE ManagerId IS NULL
--WHERE te.id = @id
WHERE ManagerId = @id
recursive self join in data.table
Here's my attempt using your dataset.
It uses a while
loop checking to see if there's any components
that also are in the prodName
field. The loop always needs to have the same fields so instead of adding a column for the recursive multipliers (i.e., 5*8*7 at the end), the iterative multipliers are integrated. That is, 5*8*7 becomes 5*56 at the end.
library(data.table)
a[, qty_multiplier := 1]
b <- copy(a)
while (b[component %in% prodName, .N] > 0) {
b <- b[a
, on = .(prodName = component)
, .(prodName = i.prodName
, component = ifelse(is.na(x.component), i.component, x.component)
, qty = i.qty
, qty_multiplier = ifelse(is.na(x.qty), 1, x.qty * qty_multiplier)
)
]
}
b[prodName %like% 'prod', .(qty = sum(qty * qty_multiplier)), by = .(prodName, component)]
prodName component qty
1: prod1 a 13
2: prod1 b 14
3: prod2 b 3
4: prod3 b 284
5: prod3 a 240
6: prod3 d 45
Recursive SQL self join
You want a recursive CTE:
with e as (
select cast(name as varchar(max)) as list, empId, 0 as level
from employees
where managerID is null
union all
select e.list + '>' + e2.name, e2.empId, level + 1
from e join
employees e2
on e.empId = e2.managerId
)
select e.*
from e
where not exists (select 1
from employees e2
where e2.managerId = e.empId
);
Recursive self join
I would simply run a short loop like this (sorry for invalid capitalization, coded from scratch):
public List<Int> GetAllManagers(int userID)
{
var result = new List<int>();
int index = 0;
result.add(userID); // start with user (it will be removed later)
while (index < result.count)
{
var moreData = from e in mycontext.EmployeeManagers
where e.UserId == result[index];
select e.ManagerId;
foreach (int id in moreData)
if (result.indexOf(id)==-1)
result.add(id);
index++;
}
result.delete(0);
return result;
}
or recursevly
private void AddUniqueIds (List<int> elements, ref List<int> list)
{
foreach (int id in elements)
if (list.indexOf(id)==-1)
list.add(id);
}
public List<int> GetAllManagers(int userID)
{
var result = new List<int>();
var moreData = from e in mycontext.EmployeeManagers
where e.UserId == result[index];
select e.ManagerId;
foreach (int id in moreData)
AddUniqueIds(result, GetAllManagers(id));
return result;
}
Related Topics
Group by Clause in MySQL and Postgresql, Why the Error in Postgresql
Inner Join VS Left Join Performance in SQL Server
MySQL Error: Key Specification Without a Key Length
String_Agg For SQL Server Before 2017
Index For Finding an Element in a Json Array
Select Values That Meet Different Conditions on Different Rows
MySQL Error:: 'Access Denied For User 'Root'@'Localhost'
Sql/MySQL - Select Distinct/Unique But Return All Columns
Auto Increment After Delete in MySQL
How to Get Column Names from a Table in SQL Server
Error 1452: Cannot Add or Update a Child Row: a Foreign Key Constraint Fails
Null in MySQL (Performance & Storage)
Select N Random Rows from SQL Server Table
How to See the Raw SQL Queries Django Is Running
Best Way to Test If a Row Exists in a MySQL Table
Rails + MySQL on Osx: Library Not Loaded: Libmysqlclient.18.Dylib