I have 2 tables:
Devices (id (PK))
Links (id (PK), device_id_1 (FK), device_id_2 (FK))
Which represents devices connected by links.
I need to select all devices connected with a given one (which can be device_id_1 or device_id_2). I tried to do it with the following query:
select d2.*
from Devices as d1
left outer join Links as l on d1.id in (l.device_id_1, l.device_id_2)
left outer join Devices as d2 on d2.id in (l.device_id_1, l.device_id_2)
where d1.id = 398 and d2.id <> 398;
But as soon as I added second JOIN
the query returns zero rows. What am I doing wrong?
SQL handles queries across more than one table through the use of JOINs. JOINs are clauses in SQL statements that link two tables together, usually based on the keys that define the relationship between those two tables.
If you have an OR condition in the JOIN - and there is no possibility that the values in the OR statement overlap...then you can convert it to a UNION ALL. If the values overlap it would require a UNION which may not improve performance over the JOIN.
A conditional column join is a fancy way to let us join to a single column and to two (or more) columns in a single query. We can accomplish this by using a case statement in the on clause of our join. A case statement allows us to test multiple conditions (like an if/else if/else) to produce a single value.
It is better to add the condition in the Join. Performance is more important than readability. For large datasets, it matters. Do you have some kind of proof, research how the placement of the mentioned predicates affects performance?
The where clause was effectively making your last left join an inner join.
To correct move the left join filter criteria to the join criteria
select d2.*
from Devices as d1
left outer join Links as l on d1.id in (l.device_id_1, l.device_id_2)
left outer join Devices as d2 on d2.id in (l.device_id_1, l.device_id_2)
and d2.id <> 398
where d1.id = 398;
A much less elegant although generally accepted approach would be...
select d2.*
from Devices as d1
left outer join Links as l on d1.id in (l.device_id_1, l.device_id_2)
left outer join Devices as d2 on d2.id in (l.device_id_1, l.device_id_2)
where d1.id = 398
and (d2.id <> 398 OR D2.ID is null)
I generally think of it this way..
When using outer joins I typically want to exclude the rows before the join occurs so the engine doesn't have to generate such a large Cartesian. In addition on outer joins, null records I want returned. However, if I apply the limit in the where clause, all the null records generated from the outer join will be removed unless I account for NULLS as well.
In this case since you're using a <>... <> can't compare to null thus it will exclude desired records as you can't use a equality check on a null value.
1 = NULL returns NULL and 1 <> NULL returns NULL; thus not true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With