问题
I'm trying to teach myself and better understand alternative methods to a UNION and discover when I can use joins.
As I'm playing with this I can't seem to get what I want without a UNION. Is it possible to write this in a single query?
SELECT DISTINCT a.id
FROM table1 a, table2 b
WHERE a.id = b.id
AND a.ind IS NULL
AND b.year >= '2017'
AND b.code IN ('01','02','03')
AND b.flag NOT IN ('F','L')
UNION
SELECT DISTINCT a.id
FROM table1 a, table3 c
WHERE a.id = c.id
AND a.ind IS NULL
AND c.area = 'MAIN'
AND SYSDATE >= c.start
Thanks in advance for any guidance or help.
回答1:
SELECT DISTINCT a.id
FROM table1 a
LEFT JOIN table2 b on b.id = a.id AND b.year >= '2017'
AND b.code IN ('01', '02', '03') AND b.flag NOT IN ('F', 'L')
LEFT JOIN table3 c ON a.id = c.id and c.area = 'MAIN' and SYSDATE >= c.start
WHERE a.ind IS NULL
AND ( b.id IS NOT NULL or c.id IS NOT NULL)
This is one of those things where the old obsolete A,B join syntax really shows it's age, when you have some conditions that must go in a specific ON clause and others that must go in the WHERE clause. It would be very difficult to write this query that way, and even harder to read and understand it later. Better to always write out the full INNER JOIN, LEFT JOIN, etc.
回答2:
Whenever you see a distinct, resources have been wasted.
SELECT a.id
FROM table1 a
where a.ind IS NULL
and ( exists (select null from table2 b
WHERE a.id = b.id
AND b.year >= '2017'
AND b.code IN ('01','02','03')
AND b.flag NOT IN ('F','L') )
or exists (SELECT null FROM table3 c
WHERE a.id = c.id
AND c.area = 'MAIN'
AND SYSDATE >= c.startdt)
)
Indexes on table2 (id,year,code,flag) and table3 (id,area,startdt) won't hurt performance. Oracle 11gR2 did not allow me to have a column named "start".
回答3:
I would use this
select a.id
from table1 a
where
a.ind is null and (
a.id in (
select b.id
from table2 b
where
b.year >= '2017'
and b.code IN ('01','02','03')
and b.flag NOT IN ('F','L')
) or
a.id in (
select c.id
from table3 c
where
c.area = 'MAIN'
and sysdate >= c.start
)
)
DISTINCT + table joins can be rewritten as IN/EXISTS most of the times. In several databases it might even select a better execution plan (e.g: Oracle)
回答4:
Please check if this works
SELECT DISTINCT a.id
FROM table1 a, table2 b, table3 c
WHERE (a.id = b.id
OR a.id = c.id)
AND a.ind IS NULL
AND (( b.year >= '2017'
AND b.code IN ('01','02','03')
AND b.flag NOT IN ('F','L'))
OR (c.area = 'MAIN'
AND SYSDATE >= c.start))
来源:https://stackoverflow.com/questions/49535872/alternative-to-union-clause