问题描述
仍在学习Oracle SQL,所以我会尽力清楚地说明这一点。
在下面,我使用带有子选择的NOT EXISTS过滤掉数据,但是如果可能的话,我需要将其转换为联接。我以为这会涉及到LEFT JOIN,但是子选择中的其他INNER JOIN却使我绊倒了。
SELECT *
FROM table1
INNER JOIN table2
ON table1.user_id = table2.user_id
AND NOT EXISTS (
SELECT 1
FROM table3
INNER JOIN table4
ON table4.event_id = table3.event_id
WHERE table3.status_id = table2.status_id
)
如何在不依赖子选择的情况下检索完全相同的结果?
解决方法
not exists
和子查询是完成此任务的正确工具。
我想您要记住的是将其重写为两个LEFT JOIN
和一个WHERE
子句,以便仅对不匹配的记录进行过滤:
SELECT t1.*,t2.*
FROM table1 t1
INNER JOIN table2 t2 ON t1.user_id = t2.user_id
LEFT JOIN table3 t2 ON t3.status_id = t2.status_id
LEFT JOIN table4 t4 ON t4.event_id = t3.event_id
WHERE t4.event_id IS NULL
但这并不等同于原始记录:如果一条记录在tabl3
中有两个匹配项,而在table4
中没有任何匹配项,那么结果集中将出现重复项。
这是一种愚蠢的解决方法,但是上述政策是否允许横向加入?
SELECT t1.*,t2.*
FROM table1 t1
INNER JOIN table2 t2 ON t1.user_id = t2.user_id
OUTER APPLY (
SELECT 1 flag
FROM table3 t3
INNER JOIN table4 ON t4.event_id = t3.event_id
WHERE t3.status_id = t2.status_id
) x
WHERE x.flag IS NULL
,
这是反连接的非常简单的示例:
SELECT table1.*,table2.*
FROM table1
INNER JOIN table2
ON table1.user_id = table2.user_id
left JOIN(
SELECT distinct table3.status_id
FROM table3
INNER JOIN table4
ON table4.event_id = table3.event_id
) t3
ON t3.status_id = table2.status_id
where t3.status_id is null;
如果Oracle优化器认为这样的转换更优化,那么它会为您自己进行转换。
,使用括号的另一种方法:
select *
from table1
join table2
on table2.user_id = table1.user_id
left join ( table3 join table4 on table4.event_id = table3.event_id )
on table3.status_id = table2.status_id
where table4.event_id is null;
我没有您的数据,因此无法正确测试。如果table3 / table4联接为每个table1 / table2返回多行,可能会出现问题,因为这样您将获得比原始查询更多的行。