Left outer join involving three tables - sql

From the 3 tables below I need to find 'John', who has a bike but not a car.
I'm trying to use this syntax
Select <> from TableA A left join TableB B on A.Key = B.Key where B.Key IS null
so in practise I create a left join from the two tables but i'm bit confused how the where B.Key IS null fits in my query.
select t1.name from
(table1 t1 join table3 on table3.table1id = t1.id join table2 t2 on table3.table2id = t2.id)
left join
(table1 t11 join table3 on table3.table1id = t11.id join table2 t22 on table3.table2id = t22.id)
on t1.name = t11.name where t2.name = 'Bike' and t22.name = 'Car';
Table1
ID
NAME
1
John
2
Nick
Table2
ID
NAME
1
Bike
2
Car
Table3
table1ID
table2ID
1
1
2
1
2
2

If you want your query to run at all cost you can go for something monstrous like this:
select name from table1
left join (select table1Id, table2.id as CarId from table3 join table2 on table2.id = table3.table2Id where table2.name = 'Car') c on id=c.table1Id
left join (select table1Id, table2.id as BikeId from table3 join table2 on table2.id = table3.table2Id where table2.name = 'Bike') b on id=b.table1Id
where CarId is null and BikeId is not null
https://dbfiddle.uk/pbftUJQL
But at the end it is a rough equivalent of straightforward
select name from table1
where not exists (select * from table3 join table2 on table2.id = table3.table2Id where table1.id=table3.table1Id and table2.name = 'Car')
and exists (select * from table3 join table2 on table2.id = table3.table2Id where table1.id=table3.table1Id and table2.name = 'Bike')
You must analyze query plans to choose variant that offer better performance. It may be this one:
select table1.name from table1 join table3 on table1.id=table3.table1Id join table2 on table2.id = table3.table2Id
where table2.name = 'Bike'
and not exists (select * from table3 t3 join table2 t2 on t2.id = t3.table2Id where table1.id=t3.table1Id and t2.name = 'Car')

From the 3 tables below I need to find John who has a bike but not a
car.
I would rather use this approach, it allows you to include additional criteria (e.g. has a bike and a truck but not a car) by modifying the having clause instead of adding additional joins:
select table1.id, table1.name
from table3
join table1 on table3.table1id = table1.id
join table2 on table3.table2id = table2.id
group by table1.id, table1.name
having count(case when table2.name = 'bike' then 1 end) > 0
and count(case when table2.name = 'car' then 1 end) = 0
PS: your original query could be written like this (it was missing aliases and where clause):
select *
from table1
left join (
table3 as table3_bike join
table2 as table2_bike on table3_bike.table2id = table2_bike.id
) on table3_bike.table1id = table1.id and
table2_bike.name = 'bike'
left join (
table3 as table3_car join
table2 as table2_car on table3_car.table2id = table2_car.id
) on table3_car.table1id = table1.id and
table2_car.name = 'car'
where table2_bike.id is not null
and table2_car.id is null
This query has the potential to grow exponentially e.g. if John has two bikes and two cars it'll return 2 x 2 = 4 rows for John. Relational division using exists or having is recommended.

Related

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 to join 3 tables in sql with or condition

I have 3 tables:
table1
inner join with table2; or:
inner join with table3
The query:
select table1.x
from table1 right outer join
table2
on table1.x = table2.x right outer join
table3
on table1.x = table3.x
but I can only see x values that are in both table2 and table3
Use left join, not right join, along with an appropriate filter condition:
select table1.x
from table1 left join
table2
on table1.x = table2.x left join
table3
on table1.x = table3.x
where table2.x is not null or table3.x is not null;
You might consider writing this using exists:
select t1.*
from table1 t1
where exists (select 1 from table2 t2 where t2.x = t1.x) or
exists (select 1 from table3 t3 where t3.x = t1.x);
That seems like a more natural way to implement your logic -- and you won't get duplicates when x is duplicated in table2 or table3.

Applying joins conditionally in SQL Server

I have some set of records, but now i have to select only those records from this set which have theeir Id in either of the two tables.
Suppose I have table1 which contains
Id Name
----------
1 Name1
2 Name2
Now I need to select only those records from table one
which have either their id in table2 or in table3
I was trying to apply or operator witin inner join like:
select *
from table1
inner join table2 on table2.id = table1.id or
inner join table3 on table3.id = table1.id.
Is it possible? What is the best method to approach this? Actually I am also not able to use
if exist(select 1 from table2 where id=table1.id) then select from table1
Could someone help me to get over this?
Use left join and then check if at least one of the joins has found a relation
select t1.*
from table1 t1
left join table2 t2 on t2.id = t1.id
left join table3 t3 on t3.id = t1.id
where t2.id is not null
or t3.is is not null
I would be inclined to use exists:
select t1.*
from table1 t1
where exists (select 1 from table2 t2 where t2.id = t1.id) or
exists (select 1 from table3 t3 where t3.id = t1.id) ;
The advantage to using exists (or in) over a join involves duplicate rows. If table2 or table3 have multiple rows for a given id, then a version using join will produce multiple rows in the result set.
I think the most efficient way is to use UNION on table2 and table3 and join to it :
SELECT t1.*
FROM table1 t1
INNER JOIN(SELECT id FROM Table2
UNION
SELECT id FROM Table3) s
ON(t.id = s.id)
Alternatively, you can use below SQL as well:
SELECT *
FROM dbo.Table1
WHERE id Table1.IN ( SELECT table2.id
FROM dbo.table2 )
OR Table1.id IN ( SELECT table3.id
FROM Table3 )

Query 2 tables with left join that id dont exist in 3rd table

I got
table1 table2 table3
id id id
name table1id customerid
table3id
How can i fetch the table1.name joining table2 where customerid = someid and table3id not exist in table2
SELECT
t1.id
t1.name
FROM
Table1 t1
LEFT JOIN Table2 t2
on t1.id = t2.table1id
LEFT JOIN Table3 t3
on t2.table3id = t3.id
AND t3.customerid = 93
WHERE
t3.id IS NULL
SELECT table1.name
INNER JOIN table2 ON table1.id = table2.table1id
WHERE table2.id NOT IN (SELECT id FROM table3)

Why can't I select from my query?

I have a query something like this (no, my tables and fields are not called by these names, but the structure is the same) -
SELECT table1.id, table2.id, table1.phone1
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table1.phone1 IS NOT NULL AND LTRIM(RTRIM(table1.phone1)) <> ''
UNION
SELECT table1.id, table2.id, table1.phone2
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table1.phone2 IS NOT NULL AND LTRIM(RTRIM(table1.phone2)) <> ''
UNION
SELECT table1.id, table2.id, table2.phone
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table2.phone IS NOT NULL AND LTRIM(RTRIM(table2.phone)) <> ''
It runs fine. But, when I try to select from it (which I will eventually try to manipulate with group bys, etc., but for now just tried a simple select), like so:
SELECT * FROM
( SELECT table1.id, table2.id, table1.phone1
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table1.phone1 IS NOT NULL AND LTRIM(RTRIM(table1.phone1)) <> ''
UNION
SELECT table1.id, table2.id, table1.phone2
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table1.phone2 IS NOT NULL AND LTRIM(RTRIM(table1.phone2)) <> ''
UNION
SELECT table1.id, table2.id, table2.phone
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table2.phone IS NOT NULL AND LTRIM(RTRIM(table2.phone)) <> '' )
I get the error:
Incorrect syntax near ')'.
What am I doing wrong?
You missed naming the subselect. Close with something like ...) sub_query_name.