如何无需CTE,按user_id获取最后一笔订单对应的product?
问题与解决方案
原始数据
user_id order product 1 1 a 1 2 b 1 3 b 2 1 a 2 2 c 3 1 c 3 2 a 3 3 a
需求
为每个唯一user_id保留一行,展示该用户最后一笔订单对应的product,预期输出:
user_id last_product 1 b 2 c 3 a
原尝试代码问题
之前用CASE WHEN的写法无法得到正确结果:
SELECT user_id , CASE WHEN order = MAX(order) THEN product END AS last_product FROM table GROUP BY 1 ORDER BY 1;
问题在于:GROUP BY user_id后,product未被聚合,数据库会随机选取该用户某一行的product;同时MAX(order)是聚合后的值,无法和每行的order做行级比较,最终会得到NULL或错误结果。
无CTE的简洁解决方案
1. 通用窗口函数写法(适用于大多数数据库:SQL Server、PostgreSQL、MySQL 8+等)
SELECT user_id, product AS last_product FROM ( SELECT user_id, product, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY "order" DESC) AS rn FROM your_table ) sub WHERE rn = 1 ORDER BY user_id;
- 逻辑:按
user_id分组,每组内按order倒序排,取行号为1的记录(即最后一笔订单) - 注意:
order是SQL关键字,需用双引号(标准SQL)或反引号(MySQL)包裹,避免语法错误
2. 子查询关联写法(通用所有SQL数据库)
SELECT t.user_id, t.product AS last_product FROM your_table t JOIN ( SELECT user_id, MAX("order") AS max_order FROM your_table GROUP BY user_id ) max_orders ON t.user_id = max_orders.user_id AND t."order" = max_orders.max_order ORDER BY t.user_id;
- 逻辑:先获取每个用户的最大订单号,再关联原表匹配用户和订单号,得到对应产品
- 若同一用户同一最大订单号有多条记录,可添加
DISTINCT确保每个用户只返回一行
3. MySQL专属简洁写法
SELECT user_id, (SELECT product FROM your_table t2 WHERE t2.user_id = t1.user_id ORDER BY `order` DESC LIMIT 1) AS last_product FROM your_table t1 GROUP BY user_id ORDER BY user_id;
- 逻辑:对每个分组的用户,通过子查询直接获取其订单倒序后的第一个产品
4. PostgreSQL专属简洁写法
SELECT DISTINCT ON (user_id) user_id, product AS last_product FROM your_table ORDER BY user_id, "order" DESC;
- 逻辑:
DISTINCT ON (user_id)保证每个用户仅返回一行,结合ORDER BY先分组再按订单倒序,直接取每组第一行
内容的提问来源于stack exchange,提问作者teogj
相关产品推荐
相关产品推荐

