【问题标题】:How to use subquery in outer join condition如何在外连接条件下使用子查询
【发布时间】:2018-06-21 18:12:48
【问题描述】:

我的数据库有客户和订单。客户可能有许多具有不同主键和创建日期的订单。

我想为客户创建一个视图,其中包含每个客户加入他们的最新订单(如果客户没有任何订单,则为 null)。

我尝试了以下

SELECT [...], c.customer_id, o.order_id
FROM customers c
LEFT OUTER JOIN [...]
LEFT OUTER JOIN [...]
[...]
LEFT OUTER JOIN orders o ON (
    o.customer_id = c.customer_id
    AND o.create_dt = (
        SELECT MAX(create_dt) FROM orders o2 WHERE o2.customer_id = c.customer_id
    )
);

但我收到以下错误

列不能外联到子查询

我发现 Oracle 不支持外连接中的子查询。实现此视图的正确方法是什么?请注意,此示例已简化,对语句的必要更改应该只影响特定的连接,因为还有多个其他连接和条件正在进行,为简单起见,此处未显示。

【问题讨论】:

    标签: sql oracle join greatest-n-per-group


    【解决方案1】:

    我使用了我自己想出的以下解决方案

    SELECT [...],
    c.customer_id,
    (select o.order_id from orders where o.customer_id = c.customer_id
        AND o.create_dt = (
            SELECT MAX(create_dt) FROM orders o2 WHERE o2.customer_id = 
              c.customer_id))
    as order_id
    FROM customers c
    LEFT OUTER JOIN [...]
    LEFT OUTER JOIN [...]
    

    基本上,这实现了我尝试通过加入实现的相同结果。为什么我不能在联接中使用子查询,但在列中我可以?使用联接与子查询来提高列性能和其他方面的优缺点通常是什么?我应该在哪些情况下使用一种或另一种?

    我认为我尝试的连接(它没有工作)更明确地表达了我想要实现的目标,很遗憾 Oracle 不支持那里的子查询。这种限制的原因是什么?

    【讨论】:

      【解决方案2】:

      您可以探索outer applycross apply 以实现您的目标。片段可能如下

      select d.*, e.*
      from   customers c
      outer apply (
          select [...], o.order_id
          from   orders o
          where  o.customer_id= c.customer_id
          order  by create_dt desc
          fetch first 1 rows only 
      ) e 
      

      欲了解更多信息,您可以访问link

      【讨论】:

      • 虽然Oracle支持非标准的outer apply,但最好使用SQL标准的关键字:left join lateralcross join lateralapply关键字是微软引入的,忽略了SQL标准)
      • 我想使用更常见的运算符来实现这一点,以保持与现有实现保持一致。此外,性能也是一个关键问题。
      • 即使LATERAL 听起来也太晦涩难懂了。真的没有更标准的方法来做到这一点,这也适用于旧的 Oracle 实现吗?
      【解决方案3】:

      我会使用GROUP BY 结合MAX

      SELECT c.customer_id, o.order_id
      FROM customers c
      LEFT OUTER JOIN orders o ON o.customer_id = c.customer_id
      LEFT OUTER JOIN (
          SELECT customer_id, MAX(create_dt) max_create
          FROM orders 
          GROUP BY customer_id
      ) t ON t.customer_id = o.customer_id AND
             t.max_create = o.create_dt 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-05
        • 2018-04-18
        • 2011-03-12
        • 1970-01-01
        • 1970-01-01
        • 2014-02-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多