Left join inside left join - sql

I have problem getting values from tables.
I need something like this
A.Id a1
B.Id b1
C.Id c1
B.Id b2
C.Id c2
C.Id c3
C.Id c4
Table A and B are joined together and also table B and C.
Table A can have one/zero or more values from table B. Same situation is for values from table C.
I need to perform left join on table A over table B and inside that left join on table B over table C.
I tried with left join from table A and B, but don't know how to perform left join inside that left join.
Is that possible? What would syntax for that look like?
edit:
Data would look like this
ZZN1 P1 NULL
ZZN1 P2 NAB1
ZZN2 P3 NAB2
ZZN2 P3 NAB3

No need to nest the left joins, you can simply flatten them and let your RDMBS handle the logic.
Sample schema:
a(id)
b(id, aid) -- aid is a foreign key to a(id)
c(id, bid) -- bid is a foreign key to b(id)
Query:
select a.id, b.id, c.id
from a
left join b on b.aid = a.id
left join c on c.bid = b.id
If the first left join does not succeed, then the second one cannot be performed either, since joining column b.id will be null. On the other hand, if the first left join succeeds, then the second one may, or may not succeed, depending if the relevant bid is available in c.

SELECT A.Name, B.Name , C.Name
FROM A
LEFT JOIN B ON A.id = B.id
LEFT JOIN C ON B.id = C.id

Related

Trying to return a select statement which show records from two tables that match records from a third table

Here is the Exercise we were given to practice our SQL refresher
Get all rows from TableA. If a match is available in both TableB and TableC, include it. This means that if data is available in TableB or TableC, but not both, data from both willbe excluded and only TableA data will be show
This is currently my full syntax I am using at the current moment.
SELECT *
FROM dbo.TableA a
LEFT JOIN dbo.TableB b ON a.ID = b.ID
LEFT JOIN dbo.TableC c ON a.ID = b.ID AND b.ID = c.ID
WHERE a.ID <100;
go
And this is the corresponding output I am getting.
I am trying to change Column B record 2 into NULL as it does not match Column C. Is there anyway I can get something like this to work, if I try this in the syntax it throws an identifier can not be found.
LEFT JOIN dbo.TableB b
on a.ID = b.ID and TableC.ID = b.ID
Expecting
All From Table A
Rows from TableB that match TableA and TableC
Rows from TableC that match TableA and TableB
Figured out my logic was a bit wrong.
I decided to try and layout the tables differently to see if that works and it ended up getting to what I needed
select *
from dbo.TableB b
inner join dbo.TableC c
on b.ID = c.ID
right outer join dbo.TableA a
on b.ID = a.ID
where a.ID < 100;
go

How to get rows from one or another joined table and then further to more joined tables depending on which first two tables were joined

I have three tables (a, b, c) and two (b and c) need to be joined to get detail data from the first table a. But the problem is that I need to do this in one query.
If I join both tables in the same query than no records are found as detail data is either in b or c, but never in both.
To further complicate things, I need to further join other tables (b2, c2) based on with the record found is from b or c.
I am using MS SQL.
The query I have now is:
select a.*, b.name1, c.name1, b2.url, c2.url
left join b on a.aID = b.aID
left join c on a.aID = c.aID
inner join b2 on b.bID = b2.bID
inner join c2 on c.cID = c2.cID
where a.date > '9/1/2016'
I searched for a few days, but no one seems to need to go after the fourth and fifth tables in the query and so couldn't find any similar answer
Is there any way to do this? Performance is not an issue as the number of records will be less than 1,000 after executing a where clause that will always limit the records from table a.
A series of left joins with inner joins as subqueries should do the trick. The subqueries pull the b/b2 and c/c2 data together for reference in the left joins with a:
select a.*, b.name1, c.name1, b2join.url, c2join.url
FROM a
LEFT JOIN b
on a.aID = b.aID
LEFT JOIN c
on a.aID = c.aID
LEFT JOIN
(SELECT b.aID, b.bID, b2.url
FROM b
INNER JOIN b2
on b.bID = b2.bID) as b2join
on b2join.aID = a.aID
LEFT JOIN
(SELECT c.aID, c.cID, c2.url
FROM c
INNER JOIN c2
on c.cID = c2.cID) as c2join
on c2join.aID = a.aID
I think a Left Join will do it, at least for the first part:
select a.*, b.name1, c.name1
left join b on a.aID = b.aID
left join c on a.aID = c.aID
where a.date > '9/1/2016'
You will get c.name1 null when data is in b table, and b.name1 will be null when data is in c table.
For the other two joins and not sure but left join could also work.
I think, it is more simple and brief way to get the same result:
select a.*, b.name1, c.name1, b2join.url, c2join.url
FROM a
LEFT JOIN b on a.aID = b.aID
LEFT JOIN c on a.aID = c.aID
LEFT JOIN b as b2join on b2join.bID = b.bID
LEFT JOIN a as c2join on c2join.cID = c.cID

Stuck on multiple table filtering query

Ok so I will try to simplify the problem that I have.
I have 4 tables:
TableA:
OneID
TableB:
OneID (FK to TableA)
TwoID (FK to TableC)
TableC:
TwoID
ThreeID (FK to TableD)
TableD:
ThreeID
I need a query to retrieve data from all 4 of these tables.
The query criteria is:
want to inner join tables A, B, C
want to join above result with table D with the following conditions:
if a record is in Table D but not in Table C, then it must always be present in the results
otherwise if a record is in Table D and Table C, then it should only be present if it is in the result of the A,B,C join
The scenario you have described is not really possible (or at least they are not really logical)
if a record is in Table D but not in Table C, then it must always be present in the results
The only way a record could be "in Table D and not in Table C" is if the foreign key is null in table D, with no link from table D to tables A or B there is no other way you could define a record as being present in D and not in C:
otherwise if a record is in Table D and Table C, then it should only be present if it is in the result of the A,B,C join
Again, the only way this could happen is with NULLABLE foreign keys. Regardless I think any of the below will get you the results you require:
SELECT A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM D
LEFT JOIN (C
INNER JOIN B
ON B.TwoID = C.TwoID
INNER JOIN A
ON A.OneID = B.OneID)
ON C.ThreeID = D.ThreeID;
Or
SELECT A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM A
INNER JOIN B
ON B.OneID = A.OneID
INNER JOIN C
ON C.TwoID = B.TwoID
RIGHT JOIN D
ON D.ThreeID = C.ThreeID
Or
SELECT A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM A
INNER JOIN B
ON B.OneID = A.OneID
INNER JOIN C
ON C.TwoID = B.TwoID
INNER JOIN D
ON D.ThreeID = C.ThreeID
UNION ALL
SELECT NULL, NULL, NULL, FourID
FROM D
WHERE ThreeID IS NULL;
Examples on SQL Fiddle
The first two have the same execution plan, it is just a matter of preference, I personally dislike using RIGHT JOIN because it makes queries feel like they in the wrong order i.e bottom to top, but this is purely my preference. The last query may perform better depending on the cardinality of your data and any indexes you have
EDIT
With your revised criteria I think the easiest way to implement this is with a UNION ALL:
SELECT A.OneID, B.TwoID, c.ThreeID, d3 = D.ThreeID
FROM A
INNER JOIN B
ON B.OneID = A.OneID
INNER JOIN C
ON C.TwoID = B.TwoID
INNER JOIN D
ON D.ThreeID = C.ThreeID
UNION ALL
SELECT NULL, NULL, NULL, ThreeID
FROM D
WHERE NOT EXISTS (SELECT 1 FROM C WHERE C.ThreeID = D.ThreeID);
Example on SQL Fiddle
I am not 100% sure I understood you correctly but I will try to help anyway. It seems that you need to do FULL OUTER JOIN on table D:
SELECT
*
FROM
TableA AS A INNER JOIN
TableB AS B ON B.A_Id = A.Id INNER JOIN
TableC AS C ON C.B_Id = B.Id FULL OUTER JOIN
TableD AS D ON D.C_Id = C.Id
If I have misunderstood your requirements and you need more complicated criteria, you could just do FULL OUTER JOIN on all the tables and put extra conditions in WHERE part:
SELECT
*
FROM
TableA AS A FULL OUTER JOIN
TableB AS B ON B.A_Id = A.Id FULL OUTER JOIN
TableC AS C ON C.B_Id = B.Id FULL OUTER JOIN
TableD AS D ON D.C_Id = C.Id
WHERE
--if a record is in Table D but not in Table C, then it must always be present in the results
(D.Id IS NOT NULL AND C.Id IS NULL) OR
(
--otherwise if a record is in Table D and Table C, then it should only be present if it is in the result of the A,B,C join
(D.Id IS NOT NULL AND C.Id IS NOT NULL) AND
--want to inner join tables A, B, C
(A.Id IS NOT NULL AND B.Id IS NOT NULL AND B.Id IS NOT NULL)
)

How to get values from tables A and C, joined by table B with default values from C when C has no key from A

here is my situation:
I have 3 tables:
A: (A_id, Name)
B: (B_id, A_id, Name)
C: (C_id, B_id, State)
What i want is to have the following resultset:
A.A_id,A.Name, C.State
the complicator is that i need State to have a default value when there is no B data to link.
In that case, i want
A.A_id, A.Name, 'Default_Value'
I dont know much of advanced Sql, so any pointers are greatly appreciated.
select
coalesce(c.State, 'default value')
from
a
left join b on a.id = b.A_id
left join c on b.B_id = c.B_id
the best visual explanation of joins I've ever seen: A Visual Explanation of SQL Joins
COALESCE() returns the first of its parameters which isn't NULL
You could use ISNULL in the select
SELECT A.A_id,A.Name, ISNULL (C.State, 'Default_Value')
from A
left join b...
left join c...
SELECT A.A_id, A.Name, COASLESCE(C.State, 'Default_Value')
FROM
A LEFT JOIN
(B INNER JOIN C ON C.B_id = B.B_id)
ON B.A_id = A.A_id
Some information on joins: What is the difference between "INNER JOIN" and "OUTER JOIN"?
What's happening here is that we are joining table B and C with an INNER JOIN where the respective B_id column is equal. The INNER specifies that results will be returned only when records exist in both tables that match the C.B_id = B.B_id condition.
The LEFT JOIN will join those combined values to table A if the matching condition exists, while still returning the records from table A if no match exists. That is, if nothing exists for the condition B.A_id = A.A_id, NULL values are returned for the columns from the right side of the join (the B and C join). We perform the COASLESCE, so that if the queried column returns with NULL, it can default to some specified value.
COALESCE has some added benefits when performing this function: http://msdn.microsoft.com/en-us/library/ms190349.aspx
One last thing, table B in your example is commonly known as a junction table (or join table, or bridge table)... http://en.wikipedia.org/wiki/Junction_table

Do I have to do a LEFT JOIN after a RIGHT JOIN?

Say I have three tables in SQL server 2008 R2
SELECT a.*, b.*, c.*
FROM
Table_A a
RIGHT JOIN Table_B b ON a.id = b.id
LEFT JOIN Table_C c ON b.id = c.id
or
SELECT a.*, b.*, c.*
FROM
Table_A a
RIGHT JOIN Table_B b ON a.id = b.id
JOIN Table_C c ON b.id = c.id
also, does it matter if I use b.id or a.id on joining c?
i.e. instead of JOIN Table_C c ON b.id = c.id, use JOIN Table_C c ON a.id = c.id
Thank you!
If it doesn't change the semantics of the query, the database server can reorder the joins to run in whichever way it thinks is more efficient.
Usually, if you want to force a certain order, you can use inline view subqueries, as in
SELECT a.*, x.*
FROM
Table_A a
RIGHT JOIN
(
SELECT *, b.id as id2 FROM Table_B b
LEFT JOIN Table_C c ON b.id = c.id
) x
ON a.id = x.id2
According to the definitions:
JOIN
: Return rows when there is at least one match in both tables
LEFT JOIN Return all rows from the left table, even if there are no matches in the right table
RIGHT JOIN Return all rows from the right table, even if there are no matches in the left table
The first option would include all raws from the 1st Join on Tables a and b even if there are no matching ones in table c, while the second statement would show only raws which match ones in table c.
regarding the second question i guess it would make a difference, since the 1st join includes all ids from table b, even though there are no matching ones in table a, so once you change your Join creterium to a.id you will get a different set of ids than b.id.
Yes, you do need a LEFT JOIN after a RIGHT JOIN
See
http://sqlfiddle.com/#!3/2c079/5/0
http://sqlfiddle.com/#!3/2c079/6/0
If you don't, the (inner) JOIN at the end will cancel out the effect of your RIGHT JOIN.
That wouldn't make any sense to have a RIGHT JOIN if you don't care. And if you care, you will have to add a LEFT JOIN after it.