Reputation: 111
I have 2 tables that I need to join. Table 1:
User |Country|
--------------
a | NZ |
a | NZ |
a | HU |
a | IL |
a | AU |
a | AU |
a | RO |
a | NZ |
a | NZ |
a | NZ |
a | GB |
a | GB |
Table 2:
User |Country| Payment
----------------------
a | GB | 20
a | AU | 20
a | | 30
The final result that I want to get is this one:
User | Country | Payment
--------------
a | NZ | 30
a | NZ | 30
a | HU | 30
a | IL | 30
a | AU | 20
a | AU | 20
a | RO | 30
a | NZ | 30
a | NZ | 30
a | NZ | 30
a | GB | 20
a | GB | 20
In the result there are 2 conditions:
1 - If the country is equal in both tables then give me the corresponding Payment, i.e. only for GB and AU in this case.
2 - If the country in table 2 is NULL then join the payment to all other countries (except GB and AU)
This thing can be done with 2 left joins, but is there a way to do it with 1? Something like CASE/IF. I looked at several examples joining with CASE, but it's not working for me.
Thanks.
Upvotes: 0
Views: 475
Reputation: 111
My solution was this one:
LEFT JOIN Countries b ON INSTR(a.geo, b.Code) <> 0
So the JOIN is possible only when the instance is matching.
Upvotes: 0
Reputation: 62841
While I would imagine 2 outer joins
would be more efficient, since you only want to use a single join
, here's one option using a subquery and conditional aggregation
:
select usr, country, coalesce(payment, defaultpayment) as payment
from (
select t1.usr, t1.country,
max(case when t1.country = t2.country then payment end) payment,
max(case when t2.country is null then payment end) defaultpayment
from t1
left join t2 on t1.usr = t2.usr
group by t1.usr, t1.country
) t
Upvotes: 1
Reputation: 1269913
This is where you want "defaulting". A left join
is handy, in fact two. The first matches to the country exactly; the second brings in the NULL
value.
select t1.*, coalesce(t2.payment, t2d.payment) as payment
from t1 left join
t2 t2
on t1.country = t2.country left join
t2 t2d
on t2d.country is null;
This is the best way to solve the problem, because it can make use of an index on t2(country)
.
There are other ways; for instance:
select t1.*
(select t2.payment
from t2
where t2.country = t.country or t2.country is null
order by (t2.country is not null) desc
) as payment
from t;
Or, you could use one explicit join
and aggregation. Or something cumbersome like this:
select t1.*, t2.payment
from t1 join
t2
on t1.country = t2.country
union all
select t1.*, t2.payment
from t1 join
t2
on t2.country is null
where t.country not in (select t2.country from t2 where t2.country is not null);
But the version with two left join
s is the best approach.
Upvotes: 1