patternsqlMinor
Dissecting Joins
Viewed 0 times
dissectingjoinsstackoverflow
Problem
Recently I asked a question in dba.stackexchange the question was about data hierarchy in sql and a guy named chris allen answered the question and I really loved it but when I try to understand that query much more I got confused.
Here's the query:
I did several approaches to crack and was in vain. I think I am missing something well my findings are given below
The part I failed to understand is the join he made even though I know the use of left join where we will get the columns of left table and on the right if no match is found it will be NULL.So I am looking for some visualization of the join happening here or some understanding of the joins in depth of this particular scenario.If the question doesn't fit here I will delete it . I also asked the same in the question I posted but there was no reply that is why I am putting a new question
Here's the query:
Res_id Res_name Man_id
1 sam 3
2 Biju 4
3 adrian Null
4 Helen 3
5 Micah 4
select
level1.res_name as level1,
level2.res_name as level2,
level3.res_name as level3,
level4.res_name as level4,
level5.res_name as level5
from resource as level1
left join resource as level2 on level1.res_id=level2.man_id
left join resource as level3 on level2.res_id=level3.man_id
left join resource as level4 on level3.res_id=level4.man_id
left join resource as level5 on level4.res_id=level5.man_id
where isnull(level1.man_id,0)=0I did several approaches to crack and was in vain. I think I am missing something well my findings are given below
- First he named four columns as each level 1,2,3 etc
- Each time he left joined the same table 4 time each with different aliases
- By giving condition on each join the table is getting changed to next level
- Where condition to specify the manager
The part I failed to understand is the join he made even though I know the use of left join where we will get the columns of left table and on the right if no match is found it will be NULL.So I am looking for some visualization of the join happening here or some understanding of the joins in depth of this particular scenario.If the question doesn't fit here I will delete it . I also asked the same in the question I posted but there was no reply that is why I am putting a new question
Solution
Try this query without the joins first:
This returns the rows where
-
the FROM clause returns the entire table:
-
the WHERE clause leaves just one row:
-
finally, the SELECT takes from it only one column:
Adding one self-join like in Chris's query,
gives you every top-level manager's direct subordinates. More specifically, the join results in the following row set:
The WHERE clause filters it down to just this:
And finally the SELECT clause returns only the names:
In the same manner, adding one more join, like this:
brings about the next level of subordinates:
-
this is the result of joining the third instance of the table to the results of the first join:
(I've shortened the table aliases for convenience:
-
this is what remains after the WHERE filter:
-
and this is what SELECT extracts from the above and gives you back:
Same continues for the rest of the joins. With your example, however, there will be no more rows, as the hierarchy in the table doesn't go deeper than two levels. Consequently, the other two columns in Chris's original q
select
level1.res_name as level1
from resource as level1
where isnull(level1.man_id,0)=0This returns the rows where
man_id isn't referencing anything. In other words, this returns the topmost-level managers only. For your particular example it works like this:-
the FROM clause returns the entire table:
level1.Res_id level1.Res_name level1.Man_id
------------- --------------- -------------
1 sam 3
2 Biju 4
3 adrian NULL
4 Helen 3
5 Micah 4-
the WHERE clause leaves just one row:
level1.Res_id level1.Res_name level1.Man_id
------------- --------------- -------------
3 adrian NULL-
finally, the SELECT takes from it only one column:
level1
------
adrianAdding one self-join like in Chris's query,
select
level1.res_name as level1,
level2.res_name as level2
from resource as level1
left join resource as level2 on level1.res_id=level2.man_id
where isnull(level1.man_id,0)=0gives you every top-level manager's direct subordinates. More specifically, the join results in the following row set:
level1.Res_id level1.Res_name level1.Man_id level2.Res_id level2.Res_name level2.Man_id
------------- --------------- ------------- ------------- --------------- -------------
1 sam 3 NULL NULL NULL
2 Biju 4 NULL NULL NULL
3 adrian NULL 1 sam 3
3 adrian NULL 4 Helen 3
4 Helen 3 2 Biju 4
4 Helen 3 2 Biju 4
5 Micah 4 NULL NULL NULLThe WHERE clause filters it down to just this:
level1.Res_id level1.Res_name level1.Man_id level2.Res_id level2.Res_name level2.Man_id
------------- --------------- ------------- ------------- --------------- -------------
3 adrian NULL 1 sam 3
3 adrian NULL 4 Helen 3And finally the SELECT clause returns only the names:
level1 level2
------ ------
adrian sam
adrian HelenIn the same manner, adding one more join, like this:
select
level1.res_name as level1,
level2.res_name as level2,
level3.res_name as level3
from resource as level1
left join resource as level2 on level1.res_id=level2.man_id
left join resource as level3 on level2.res_id=level3.man_id
where isnull(level1.man_id,0)=0brings about the next level of subordinates:
-
this is the result of joining the third instance of the table to the results of the first join:
1.Res_id 1.Res_name 1.Man_id 2.Res_id 2.Res_name 2.Man_id 3.Res_id 3.Res_name 3.Man_id
-------- ---------- -------- -------- ---------- -------- -------- ---------- --------
1 sam 3 NULL NULL NULL NULL NULL NULL
2 Biju 4 NULL NULL NULL NULL NULL NULL
3 adrian NULL 1 sam 3 NULL NULL NULL
3 adrian NULL 4 Helen 3 2 Biju 4
3 adrian NULL 4 Helen 3 5 Micah 4
4 Helen 3 2 Biju 4 NULL NULL NULL
4 Helen 3 5 Micah 4 NULL NULL NULL
5 Micah 4 NULL NULL NULL NULL NULL NULL(I've shortened the table aliases for convenience:
1 stands for level1, 2 for level2, and 3 for level3)-
this is what remains after the WHERE filter:
1.Res_id 1.Res_name 1.Man_id 2.Res_id 2.Res_name 2.Man_id 3.Res_id 3.Res_name 3.Man_id
-------- ---------- -------- -------- ---------- -------- -------- ---------- --------
3 adrian NULL 1 sam 3 NULL NULL NULL
3 adrian NULL 4 Helen 3 2 Biju 4
3 adrian NULL 4 Helen 3 5 Micah 4-
and this is what SELECT extracts from the above and gives you back:
level1 level2 level3
------ ------ ------
adrian sam NULL
adrian Helen Biju
adrian Helen MicahSame continues for the rest of the joins. With your example, however, there will be no more rows, as the hierarchy in the table doesn't go deeper than two levels. Consequently, the other two columns in Chris's original q
Code Snippets
select
level1.res_name as level1
from resource as level1
where isnull(level1.man_id,0)=0level1.Res_id level1.Res_name level1.Man_id
------------- --------------- -------------
1 sam 3
2 Biju 4
3 adrian NULL
4 Helen 3
5 Micah 4level1.Res_id level1.Res_name level1.Man_id
------------- --------------- -------------
3 adrian NULLlevel1
------
adrianselect
level1.res_name as level1,
level2.res_name as level2
from resource as level1
left join resource as level2 on level1.res_id=level2.man_id
where isnull(level1.man_id,0)=0Context
StackExchange Database Administrators Q#34011, answer score: 6
Revisions (0)
No revisions yet.