【问题标题】:PostgreSQL Referencing Outer Query in SubqueryPostgreSQL 在子查询中引用外部查询
【发布时间】:2015-11-17 23:37:19
【问题描述】:

我有两个 Postgres 表(实际上,不止于此,但出于问题的目的进行了简化)- 一个是客户订购的产品的记录,另一个是每个客户价格的历史记录和他们购买的日期生效。像这样的:

'订单'表

customer_id | timestamp           | quantity
------------+---------------------+---------
1           | 2015-09-29 16:01:01 | 5
1           | 2015-10-23 14:33:36 | 3
2           | 2015-10-19 09:43:02 | 7
1           | 2015-11-16 15:08:32 | 2

'价格'表

customer_id | effective_time      | price
------------+---------------------+-------
1           | 2015-01-01 00:00:00 | 15.00
1           | 2015-10-01 00:00:00 | 12.00
2           | 2015-01-01 00:00:00 | 14.00

我正在尝试创建一个查询,该查询将返回该客户在下订单时的每个订单及其单价,如下所示:

想要的结果

customer_id | quantity | price
------------+----------+------
1           | 5        | 15.00
1           | 3        | 12.00
2           | 7        | 14.00
1           | 2        | 12.00

这基本上是我想要的,但我知道您不能在内部查询中引用外部查询,而且我无法弄清楚如何重构:

SELECT
    o.customer_id,
    o.quantity,
    p.price
FROM orders o
    INNER JOIN (
        SELECT price
        FROM prices x
        WHERE x.customer_id = o.customer_id
            AND x.effective_time <= o.timestamp
        ORDER BY x.effective_time DESC
        LIMIT 1
    ) p
;

谁能提出最好的方法来完成这项工作?

【问题讨论】:

  • 如果使用join lateral,可以在join查询中引用orders表。

标签: sql postgresql


【解决方案1】:

您可以在 SELECT 列表中执行子查询,而不是加入基于 prices 表的内联视图:

SELECT customer_id, quantity, (
    SELECT price
    FROM prices p
    WHERE
      p.customer_id = o.customer_id
        AND p.effective_time <= o.timestamp
    ORDER BY p.effective_time DESC
    LIMIT 1
  ) AS price
FROM orders o

这确实依赖于相关子查询,这可能不利于性能,但根据您的数据结构方式,我怀疑是否有更好的选择。

【讨论】:

  • 好的,是的,这是有道理的。我会试一试,希望性能不会成为问题。谢谢!
【解决方案2】:

您不需要子查询,只需简单的内部连接即可(假设每个客户没有重复的有效时间):

SELECT o.customer_id, o.quantity
    ,p.price
FROM orders o
JOIN prices p ON p.customer_id = o.customer_id
              AND p.effective_time <= o.timestamp
              AND NOT EXISTS ( SELECT * FROM prices nx
                  WHERE nx.customer_id = o.customer_id
                  AND nx.effective_time <= o.timestamp
                  AND nx.effective_time > p.effective_time
              )
    ;

【讨论】:

  • 好吧...有趣。那可以工作。不过,它仍然有一个子查询——您知道与上面@JohnBollinger 的答案相关的性能如何吗?
  • 性能可能是一样的。只有使用 rownumber() over(按 customer_id ORDER BY Effective_time DESC 分区)的子查询可能会执行得更好。
猜你喜欢
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多