Postgres - 获取所有客户和最新订单

时间:2016-02-13 00:15:45

标签: sql postgresql greatest-n-per-group

我有一种感觉,当我得到回答时,我会感到愚蠢。我有一张客户表和一张订单表。我想要一个查询,它给我一个所有客户的列表,以及它们的最后订单信息(如果有的话),按客户名称排序。

    SELECT c.id, c.name, o.order_time, o.item_name
    FROM clients AS c LEFT JOIN(
        SELECT client_id, max(order_time) AS order_time
        FROM orders GROUP BY client_id
    ) AS o
    ON(c.id = o.client_id)
    ORDER BY UPPER(c.name)"

我的问题是,如果删除o.item_name,我会得到我想要的行,但是所写的查询是无效的,因为如果没有将o.item_name放在GROUP BY中,就无法获取o.item_name。当然,这会导致它为每个客户端返回多行。希望我的意图很明确。

2 个答案:

答案 0 :(得分:2)

您可以使用窗口功能执行此操作:

SELECT c.id, c.name, o.order_time, o.item_name
FROM clients AS c 
  LEFT JOIN (
    SELECT client_id, 
           item_name,
           order_time,
           row_number() over (partition by client_id order by order_time desc) as rn
    FROM orders 
  ) AS o ON c.id = o.client_id and o.rn = 1
ORDER BY UPPER(c.name);

另一个选择是使用Postgres'distinct on()运算符,它通常比使用窗口函数的解决方案更快:

SELECT c.id, c.name, o.order_time, o.item_name
FROM clients AS c 
  LEFT JOIN (
    SELECT distinct on (client_id) client_id, 
           item_name,
           order_time
    FROM orders 
    order by client_id, order_time desc
  ) AS o ON c.id = o.client_id 
ORDER BY UPPER(c.name);

答案 1 :(得分:0)

在Postgres中,您可以使用distinct on

SELECT DISTINCT ON (c.name) c.id, c.name, o.order_time, o.item_name
FROM clients c LEFT JOIN
     orders o
    ON c.id = o.client_id
ORDER BY UPPER(c.name), o.order_time DESC;