替代子查询的外连接?

时间:2014-02-26 16:37:03

标签: sql oracle scalar-subquery

Oracle显然不允许对子查询进行外连接。对于表A中的每一行,我正在尝试在表B上找到具有相同ID和最新日期的行。

这样的事情:

SELECT a.*, b.date, b.val1, b.val2
FROM a, b
WHERE b.id (+) = a.id
  AND b.date (+) = (SELECT MAX(b.date) FROM a, b WHERE a.id = b.id);

删除b.date上的外连接(+)允许对其进行解析,但是当表B上没有行时不返回任何行。在这种情况下,我需要查询只返回NULL。有办法解决这个问题吗?

由于

4 个答案:

答案 0 :(得分:4)

我认为你想要的是:

SELECT a.*, b.date, b.val1, b.val2
FROM a
LEFT JOIN b ON b.id = a.id
WHERE (b.date is null 
       or b.date = (SELECT MAX(b2.date) FROM b b2 WHERE a.id = b2.id));

这样,外连接只在id上执行。然后,我们会过滤掉b.datemax对应行a不是a的所有行。

另外,您会注意到我从子查询中删除了b。最初编写时,子查询返回amax(date)中具有{{1}}中相应行的最大日期。外部查询的每一行都将使用相同的值。修订版本使子查询与外部查询相关(即,它将为返回的每一行获得相应的{{1}}。

答案 1 :(得分:3)

我已经投票支持Allan的答案,但只是为了演示另一种方法,以下是如何使用分析函数完成的:

SELECT * FROM (
  SELECT a.*, b.date, b.val1, b.val2,
    ROW_NUMBER() over (PARTITION BY a.id ORDER BY b.date DESC) r
  FROM a LEFT JOIN b ON a.id=b.id
)
WHERE r=1

即使有多个a.id行具有最大日期,每个b也只会包含一行。要包含所有这些内容,请将ROW_NUMBER更改为RANK

答案 2 :(得分:0)

编辑:您可以将最大日期保存到变量

DECLARE @maxDate as datetime
SET @maxDate = (SELECT MAX(date) FROM b)

SELECT a.*, b.date, b.val1, b.val2
FROM a
LEFT OUTER JOIN b ON a.id = b.id
  AND b.date = @maxDate

这可能比Allan的答案更有效或更低效,这取决于A是否有比B更多的行(反之亦然)。如果B有很多行,那么查询它两次(我的答案就是这样)可能不是最佳解决方案。

答案 3 :(得分:0)

标量子查询怎么样?

select a.*, (select max(b.date) from b where b.id = a.id) as b_date
from a;