Reputation: 1019
I have a table that has 2 column, usersID
and their siblingID
What is the best way to find all the siblings of a given user?
The issue is complex. Here is an example.
User 1 has 5 siblings(2,3,4,5,6)
The table looks like this
userID|siblingID
1 | 2
1 | 3
6 | 5
5 | 3
3 | 1
4 | 6
Upvotes: 1
Views: 811
Reputation: 1269613
The answer, even using more than one SQL statement, was much harder than I thought it would be.
The easy answer to your question is: create a table with all sibling relationships. Then you can just query this as:
select siblingid
from @allsiblings sa
where sa.userid = 3
One note. I'm using the syntax of SQL Server, just because that happens to be the most handy database. I'm only using functionality in MySQL so it should be easy to translate.
How to create the table @AllSiblings? Well, just keep on adding sibling pairs in that don't exist, until there are no more to add. We get the pairs by doing a self join.
Here is the code (subject to the previous caveat):
declare @allsiblings table (userid integer, siblingid integer);
declare @siblings table (userId int, siblingID int);
-- Initialize the @siblings table
insert into @siblings(userId, siblingID)
select 1 as userID, 2 as siblingID union all
select 1 as userID, 3 as siblingID union all
select 6 as userID, 5 as siblingID union all
select 5 as userID, 3 as siblingID union all
select 3 as userID, 1 as siblingID union all
select 4 as userID, 6 as siblingID;
-- Initialize all siblings. Note that both pairs are going in here
insert into @allsiblings(userid, siblingid)
select userId, siblingid from @siblings union
select siblingID, userid from @siblings
-- select * from @allsiblings
while (1=1)
begin
-- Add in new siblings, that don't exist by doing a self-join to traverse the links
insert into @allsiblings
select distinct sa.userid, sa2.siblingid
from @allsiblings sa join
@allsiblings sa2
on sa.siblingid = sa2.userid
where not exists (select * from @allsiblings sa3 where sa3.userid = sa.userid and sa3.siblingid = sa2.siblingid)
-- If nothing was added, we are done
if (@@ROWCOUNT = 0) break;
select * from @allsiblings;
end;
Upvotes: 1
Reputation:
ANSI SQL:
with recursive tree (userid, siblingid) as
(
select userid,
siblingid
from users
where userId = 1
union all
select c.userid,
c.siblingid
from users c
join tree p on p.userid c.siblingId
)
select *
from tree;
For Oracle 11.2 and SQL Server - who apparently didn't look at the ANSI specs closely - you need to remove the recursive
keyword (it is mandatory according to the standard)
Upvotes: 3
Reputation: 340
http://sqlfiddle.com/#!4/0ef0c/5 is an example where someone had to get all the relatives of certain entries.
The corresponding stack overflow question is here: Hierarchical Query Needs to Pull Children, Parents and Siblings
Upvotes: 0
Reputation: 12837
you can simulate recursion with a loop and a temp table. first insert in the temp table the start node. then while there are rows in the temp table, get the first one, delete it from the temp table and in it's place insert all his siblings...
Upvotes: 0