Multiple Full Outer Joins - sql

I want to use the result of a FULL OUTER JOIN as a table to FULL OUTER JOIN on another table. What is the syntax that I should be using?
For eg: T1, T2, T3 are my tables with columns id, name. I need something like:
T1 FULL OUTER JOIN T2 on T1.id = T2.id ==> Let this be named X
X FULL OUTER JOIN T3 on X.id = t3.id
I want this to be achieved so that in the final ON clause, I want the T3.id to match either T1.id or T2.id. Any alternative way to do this is also OK.

SELECT COALESCE(X.id,t3.id) AS id, *-- specific columns here instead of the *
FROM
(
SELECT COALESCE(t1.id,t2.id) AS id, * -- specific columns here instead of the *
FROM T1 FULL OUTER JOIN T2 on T1.id = T2.id
) AS X
FULL OUTER JOIN T3 on X.id = t3.id

Often, chains of full outer joins don't behave quite as expected. One replacements uses left join. This works best when a table has all the ids you need. But you can also construct that:
from (select id from t1 union
select id from t2 union
select id from t3
) ids left join
t1
on ids.id = t1.id left join
t2
on ids.id = t2.id left join
t3
on ids.id = t3.id
Note that the first subquery can often be replaced by a table. If you have such a table, you can select the matching rows in the where clause:
from ids left join
t1
on ids.id = t1.id left join
t2
on ids.id = t2.id left join
t3
on ids.id = t3.id
where t1.id is not null or t2.id is not null or t3.id is not null

You can do it like you suggested, using IN()
FROM T1
FULL OUTER JOIN T2
ON(T1.id = T2.id)
FULL OUTER JOIN T3
ON(T3.ID IN(T2.id,T1.id))
or I think you can do it with a UNION (depends on what you need) :
SELECT * FROM
(SELECT name,id from T1
UNION
SELECT name,id from T2) x
FULL OUTER JOIN T3
ON(t3.id = x.id)

Related

LEFT OUTER JOIN behaves like INNER JOIN [duplicate]

This question already has answers here:
Problems with INNER JOIN and LEFT/RIGHT OUTER JOIN
(5 answers)
Closed 2 years ago.
I have 3 tables: T1, T2, T3
I need to have all rows from T1 in result and if there are matching records in T2 and T3, then output them also.
So my query looks like
SELECT *
FROM T1
LEFT JOIN T2
ON T1.Id = T2.Id
INNER JOIN T3
ON T2.SecondId = T3.Id
But in result, I receive only records that have some records in T3.
Is it the same behavior as I would write
SELECT *
FROM T1
LEFT JOIN T2
ON T1.Id = T2.Id
WHERE T2.Value = 4
where LEFT JOIN behaves like INNER JOIN because of WHERE clause?
The syntax for what you probably want is:
SELECT *
FROM T1 LEFT JOIN
T2
ON T1.Id = T2.Id LEFT JOIN
T3
ON T2.SecondId = T3.Id
Without the second LEFT JOIN, the INNER JOIN filters out non-matches. That is because T2.SecondId will be NULL for those non-matches. This is the right approach; checking explicitly for NULLs has some edge cases that don't work.
For the second query:
SELECT *
FROM T1 LEFT JOIN
T2
ON T1.Id = T2.Id AND T2.Value = 4

How do I look for non-matching values across 3 SQL tables?

I'm looking to do what I believe is a double-nested check across three tables, but have no idea how to do so.
I have Table1, Table2, and Table3.
All are tied by an ID and a "Longform" and "Shortform" in Table1:
I'm trying to find:
Entries whose IDs appear in Table2 that have the same Longform as those in Table3, but don't share the same Shortform.
This is about as far as I've gotten:
SELECT T2.Longform,T2.Shortform FROM(
SELECT Table1.Longform,Table1.Shortform,Table1.ID FROM OuterTable1.Table1
LEFT JOIN OuterTable2.Table2 on Table1.ID = Table2.ID)
WHERE Table2.ID IS NOT NULL) T2
;
I know I'm probably going to have to do another nested select, or a join, on Outertable3.Table3 but I'm not sure which... Or where...
Any help appreciated as always.
Try the following:
Select *
(
Select T1.*
from T2
inner join T1
on T1.ID = T2.ID
) as Tab
inner join
(
Select T1.*
from T3
inner join T1
on T1.ID = T3.ID
) as Tab2
on Tab.id = Tab2.id
and Tab.Longform = Tab2.Longform
and Tab.Shortform <> Tab2.Shortform
To get the longform join table1 to table2 or table3. Then use EXISTS to check in a subquery if the IDs of table1 are different but the longform is equal.
SELECT *
FROM table2 t21
INNER JOIN table1 t11
ON t11.id = t21.id
WHERE EXISTS (SELECT *
FROM table3 t32
INNER JOIN table1 t12
ON t12.id = t32.id
WHERE t12.id <> t11.id
AND t12.longform = t11.longform);
Assuming ID is unique in all three tables
Select t2.id,t2.shortform, t1.shortform AS shortformTab1, t2.longform
FROM table2 t2
JOIN table3 t3
ON t2.id = t3.id AND t2.longform = t3.longform
JOIN table1 t1
ON t2.id = t1.id AND t2.shortform != t1.shortform

How do I get the results of one JOIN and THEN feed those into a separate join in T-SQL?

I'm trying to JOIN 2 tables ON a key like
SELECT column1,column2
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.t2id = t2.id
Now, I have a 3rd table that has a Foreign Key with t2's id that I want to join... When I do
LEFT JOIN
Table3 t3 ON t3.t2id = --<-------------- This is where I'm lost
I don't know if I should do ON t3.t2id = t1.t2id OR ON t3.t2id = t2.id
What I need is the list of t2ids which are still in the picture after the first join. However, it seems as though if I specify either of the above, it will just pull ids from the original table before the first join?
To clarify one more time: I'm trying to essentially do a INNER JOIN of Table1 and Table2, get the resulting table, then get the t2ids of those results and feed them into a final join such that the final result contains all of Table3's rows as well as the data from the first join
You said: "final result contains all of Table3's rows as well as the data from the first join".
It means that you need
Table3 LEFT JOIN <previous results>
instead of
<previous results> LEFT JOIN Table3
The easiest way to write it is to use Common-Table Expressions:
WITH
CTE_InnerJoin
AS
(
SELECT column1, column2, t1.t2id
FROM
Table1 t1
INNER JOIN Table2 t2 ON t1.t2id = t2.id
)
SELECT
CTE_InnerJoin.column1
,CTE_InnerJoin.column2
,Table3....
FROM
Table3
LEFT JOIN CTE_InnerJoin ON CTE_InnerJoin.t2id = Table3.t2id
;
It doesn't matter what column you include in the CTE: t1.t2id or t2.id, the values in them are the same, because they are inner-joined together.
JOINs already do exactly what you want. A JOIN isn't always between two tables. Frequently, it's between the results of previous joins.
SELECT column1,column2
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.t2id = t2.id
LEFT JOIN
Table3 t3 ON t3.t2id = t2.id
At the point at which you're writing the final ON clause here, what you're joining is precisely the results of the previous INNER JOIN on the left and the table Table3 on the right. All of t1, t2 and t3 are in scope within the ON clause, but note that t1 and t2 are now both used as aliases into the same source of rows - the previous INNER JOIN.
As a further example, consider the "diamond join":
SELECT
*
FROM
t1
left join
t2
on
t1.a = t2.b
left join
t3
on
t1.c = t3.d
inner join
t4
on
t2.e = t4.f OR
t3.g = t4.h
This is a way of joining two tables (t1 and t4) based on two alternative joins. Note that in the final inner join, what is on the "left" is the result of already joining tables t1, t2 and t3.
Join the table having foreign key with
Try this....
SELECT column1,column2
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.t2id = t2.id
LEFT join Table3 t3 ON t2.id=t3.t2id
Or Like this.
SELECT t12.column1 ,
t12.column2 ,
t3.*
FROM (
--- INNER JOIN of Table1 and Table2, get the resulting table,
SELECT t1.column1 ,
t2.column2 ,
t1.t2id --- or t2.id doesn't matter because its inner join
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.t2id = t2.id
) T12
LEFT JOIN Table3 T3 ON t3.t2id = t1.t2id --- then get the t2ids of those results
--- and feed them into a final join
--- if you want to get all rows from Table3, Change LEFT JOIN Table3 T3 ON t3.t2id = T1.t2id
--- into RIGHT JOIN Table3 T3 ON t3.t2id = T1.t2id
try this
select t3.*, column1, column2
from
table1 t1 inner join table2 t2 on t1.t2id = t2.id
right outer join table3 t3 on t3.t2id = t2.id
equvalent to
select t3.*, column1, column2
from
table1 t1 inner join table2 t2 on t1.t2id = t2.id
right outer join table3 t3 on t3.t2id = t1.t2id
if you want all rows from table 3 and those matching rows from table1 inner joined to table2 then you can use this syntax:
select t3.*,
column1, column2
from table3 t3
left join table2 t2
inner join table1 t1
on t1.t2id = t2.id
on t3.t2id = t2.id

Convert to join query

select t.* from table1 t where t.id NOT IN(
select Id from t2 where usrId in
(select usrId from t3 where sId=value));
I the result i need is like if there are matching id's in t1 and t2 then those id's should be omitted and only the remaining rows should be given to me. I tried converting into join but it is giving me the result i wanted. Below is my join query.
SELECT t.* FROM table1 t JOIN table2 t2 ON t.Id <> t2.Id
JOIN table3 t3 ON t3.Id=t2.Id WHERE t3.sId= :value
This doesn't feth me the correct result. it was returning all the rows, but i want to restrict the result based on the matching id's in table t1 and table t2. Matching id's should be ommited from the result.I will be passing the value for sId.
I believe this to be an accurate refactor of your query using joins. I don't know if we can do away with the subquery, but in any case the logic appears to be the same.
select t1.*
from table1 t1
left join
(
select t2.Id
from table2 t2
inner join table3 t3
on t2.usrId = t3.usrId
where t3.sId = <value>
) t2
on t1.Id = t2.Id
where t2.Id is null
Let's break down and solve problem step by step.
So your query
select t.* from table1 t where t.id NOT IN(
select Id from t2 where usrId in
(select usrId from t3 where sId=value));
on converting the inner query to JOIN will yield
select t.* from table1 t where t.id NOT IN
(SELECT T2.ID FROM T2 JOIN T3 on T2.UsrID =T3.UsrID and T3.sID=value)
which on further converting to JOIN with outer table will be
select t.* from table1 t LEFT JOIN
(SELECT T2.ID FROM T2 JOIN T3 on T2.UsrID =T3.UsrID and T3.sID=value)t4
ON t.id =T4.ID
WHERE t4.ID is NULL
In case you completely want to remove sub-query you can try like this
SELECT t.*
FROM table1 t
LEFT JOIN T2
ON T.ID=T2.ID
LEFT JOIN T3
ON T3.UsrId=T2.UsrID AND T3.sId=value
WHERE T3.UsrID IS NULL

join with the on supplied later

I have a query in the following format
select
*
from
Table1 t1
inner join Table2 t2
inner join Table3 t3 on t2.ID = t3.ID
on t3.ID = t1.ID
What I do know:
Not providing the last on condition results in an error.
Additionally changing the first join condition from on t2.ID = t3.ID to on t1.ID = t2.ID results in an error that t1.ID could not be bound.
Obviously the above examples are arbitrary and may not actually produce a practically useful result. However, an explanation of what providing the on later is actually doing would be great.
Thanks
EDIT
I'm not trying to change the question to something that works but to understand what MSSQL is doing when I provide it.
You can use the format you specified (presuming the correct table aliases), if you use parenthesis.
Select ... -- never use Select *
From (Table1 As T1
Join Table2 As T2
On T2.ID = T1.ID)
Join Table3 As T3
On T3.ID = T1.ID
However, with equi-joins (inner joins) it really makes no difference and it is easier to read if you do not use parenthesis. However, this format is very useful with outer joins. Take the following two examples:
Example 1
Select ...
From Table1 As T1
Left Join Table2 As T2
On T2.T1_ID = T1.ID
Join Table3 As T3
On T3.T2_ID = T2.ID
Example 2
Select ...
From Table1 As T1
Left Join (Table2 As T2
Join Table3 As T3
On T3.T2_ID = T2.ID)
On T2.T1_ID = T1.ID
Suppose in this situation, that T3.T2_ID is a non-nullable foreign key to Table2. In Example1, the Inner Join to Table3 will effectively filter out rows that would have been null because the given T2.T2_ID does not exist in Table1. However, in the second example, the join between Table2 and Table3 is done before the Left Join to Table1 is processed. Thus, we'll get the same rows from Table1 and Table2 as:
Example 3
Select ...
From Table1 As T1
Left Join Table2 As T2
On T2.T1_ID = T1.ID
Assuming you meant t1 rather than t, then your query:
select
*
from
Table1 t1
inner join Table2 t2
inner join Table3 t3 on t2.ID = t3.ID
on t3.ID = t1.ID
...can be made rather more clear by the addition of the brackets it doesn't really need:
select
*
from
Table1 t1
inner join
(Table2 t2 inner join Table3 t3 on t2.ID = t3.ID) on t3.ID = t1.ID
Effectively, you're explicitly saying "join t2 to t3, then join t1 to that."
Does that help?
First off--you don't define what t is
Table1 is aliased t1
Table2 is aliased t2
Table3 is aliased t3
But there is no plain t.
Second, you are not doing a join of t1 to t2, but of t1 to t3 and then t3 to t2. That will work. If there is a relation between t1 and t2 (t1.ID=t2.ID) then that "on" statement should directly follow the inner join statement for t2:
select
*
from
Table1 t1
inner join Table3 t3 on t1.ID = t3.ID
inner join Table2 t2 on t3.ID = t2.ID
UPDATE (based on your update)
are t1.ID, t2.ID, and t3.ID all the same data type?