我有一个表用户和一个表命令。
表用户具有主键user_id
和其他一些字段。表格订单包含外键user_id
,名称order_name
和日期order_date
。
对于旧版导出,我需要构建一个返回表单中数据的查询
user_id | order_name1 | order_name2 | order_name3
订单1-3是客户最近的三个订单。
我的想法是查询客户并使用select to orders进行三次连接
SELECT
users.*,
order1.order_name AS order_name1,
order2.order_name AS order_name2,
order3.order_name AS order_name3
FROM users AS users
JOIN (
SELECT
user_id,
order_name,
order_date
FROM orders ORDER BY order_date DESC OFFSET 0 LIMIT 1)
AS order1 ON order1.user_id=users.user_id
JOIN (
SELECT
user_id,
order_name,
order_date
FROM orders ORDER BY order_date DESC OFFSET 1 LIMIT 1)
AS order2 ON order2.user_id=users.user_id
JOIN (
SELECT
user_id,
order_name,
order_date
FROM orders ORDER BY order_date DESC OFFSET 2 LIMIT 1)
AS order3 ON order3.user_id=users.user_id
但是,这不起作用,因为它只从订单返回一行,而不是专门为每个用户返回。
如何编写这样的查询?
答案 0 :(得分:2)
您可以使用window function为每个用户编号行:
SELECT users.*,
o.order_name,
o.rn as order_number
FROM users AS users
JOIN ( SELECT user_id,
order_name,
order_date,
row_number() over (Partition by user_id) order by order_date desc as rn
FROM orders
) AS o ON o.user_id = users.user_id and o.rn <= 3;
但是上面的内容不会给你三列,而是每个用户有三行。要将其转换为列,您需要应用group by
来应用穷人的数据透视模式:
SELECT users.user_id,
max(case when o.rn = 1 then o.order_name end) as order_name1,
max(case when o.rn = 2 then o.order_name end) as order_name2,
max(case when o.rn = 3 then o.order_name end) as order_name3
FROM users AS users
JOIN ( SELECT user_id,
order_name,
order_date,
row_number() over (Partition by user_id) order by order_date desc as rn
FROM orders
) AS o ON o.user_id = users.user_id and o.rn <= 3;
GROUP BY users.user_id;
如果users.user_id
是该表的主键,则可以从users
表中添加其他列,而无需将其添加到group by
。
自Postgres 9.4以来,表达式
max(case when o.rn = 1 then o.order_name end) as order_name1
也可以写成:
max(o.order_name) filter (where o.rn = 1) as order_name1