【问题标题】:Alternative to an outer join to a subquery?替代子查询的外部联接?
【发布时间】:2014-02-26 16:37:02
【问题描述】:

显然,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。有没有办法解决这个问题?

谢谢

【问题讨论】:

  • 你为什么不能使用order by b.date desc
  • 谢谢 - 我需要从 B 中选择其他几个字段。更新了问题。
  • 没关系,因为您关心的是最新日期的行,您仍然可以使用 order by
  • 好的。我还需要从另一个表 C 中选择一些匹配的行。你能举一个例子说明这将如何工作吗?谢谢
  • 你并不完全清楚你想要什么为空。如果不是最大值,您是否希望 B 中的日期为空?或者如果日期不是最大值,您是否希望 B 中的所有内容都为空?

标签: sql oracle scalar-subquery


【解决方案1】:

我想你想要的是这样的:

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.date 不是max 的行,以对应a 中的对应行。

顺便说一句,您会注意到我从子查询中删除了a。正如最初编写的那样,子查询返回b 中的最大日期,该日期在a 中有相应的行。外部查询的每一行都将使用相同的值。修改后的版本使子查询与外部查询相关联(即,它将为返回的每一行获取相应的max(date))。

【讨论】:

  • 这是一个很好的答案,我赞成。根据每个表中有多少行,它可能比我的答案更有效或更低。
  • @DouglasBarbin:我们的答案实际上提供了不同的结果。你的在所有b 表中获得一个max(date),而我的为每个唯一的b.id 获得max(date)。根据正确解释的问题尚不清楚。
  • 我刚刚在 OP 上发表了类似的评论。
  • 我的也有所不同,因为它不会对 A 中日期不是表的最大值的行执行与 B 的连接。您的将始终加入 id,然后根据 B 中的日期是否是给定 id 的最大值来消除行。所以这两个查询实际上比我最初意识到的要不同。
【解决方案2】:

我已经为 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

【讨论】:

  • 我对此表示赞同,因为由于(<predicate> OR <sub-query>) 的执行方式,它可能优于艾伦的答案。
【解决方案3】:

标量子查询怎么样?

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

【讨论】:

  • 他需要 B 中的其他几列,并且(我认为)他只想对 B 中具有最大日期的行执行连接。
  • 我认为你是对的 - 但当我回答他的问题时,不想要 B 的任何其他列,这是后来添加的!
【解决方案4】:

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

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

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

【讨论】:

  • 否 - 收到错误“列可能未外连接到子查询”。
  • OP 已指定这是一个 Oracle 问题。这似乎是一个 SQL Server 解决方案。
  • @Allan 是的,我通常不使用 Oracle。是否有任何非标准 SQL?
  • Oracle 不使用 @ 表示变量,并且不允许在不使用游标的情况下从程序块返回结果集。
  • 啊,我每天都学到新东西。我远非 SQL 大师。谢谢你的知识。
猜你喜欢
  • 2016-07-25
  • 1970-01-01
  • 2012-03-31
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多