You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL左连接返回多行问题:合并OLI或取首行的方法

解决PostgreSQL LEFT JOIN返回多行的两种方案

这是关联查询里非常常见的问题,我给你两种精准匹配需求的解决思路:

方案一:将同一订单的OLI合并为集合返回

PostgreSQL提供了专门的聚合函数来把多行结果合并成集合,常用的有两种:

1. 使用array_agg()生成数组

如果你想把OLI的某个字段(比如SKU、数量)合并成数组,或者把整个OLI行合并成数组,可以这么写:

SELECT 
    o.*,
    -- 合并特定字段为数组,比如OLI的SKU
    array_agg(oli.sku) AS oli_skus,
    -- 合并整个OLI行成数组
    array_agg(oli) AS all_olis
FROM orders o
LEFT JOIN order_line_items oli ON o.id = oli.order_id
GROUP BY o.id; -- 按订单分组,确保每个订单只返回一行

如果担心重复的OLI,可以加上DISTINCT:array_agg(DISTINCT oli.sku);如果订单没有匹配的OLI,想返回空数组而不是NULL,可以用COALESCE(array_agg(oli), '{}'::json[])来处理。

2. 使用json_agg()生成JSON数组

如果需要更易读的JSON格式结果,推荐用json_agg():

SELECT 
    o.*,
    json_agg(oli) AS oli_json_array
FROM orders o
LEFT JOIN order_line_items oli ON o.id = oli.order_id
GROUP BY o.id;

这个会把所有匹配的OLI转换成一个JSON数组,非常适合后续应用层解析。

方案二:仅返回每个订单的首个OLI

如果你只需要保留每个订单的第一条OLI(可以自定义“首个”的规则,比如按ID、创建时间排序),有两种简洁的实现方式:

1. 使用PostgreSQL专属的DISTINCT ON语法

这是PostgreSQL特有的高效写法,语法简洁性能好:

SELECT DISTINCT ON (o.id)
    o.*,
    oli.*
FROM orders o
LEFT JOIN order_line_items oli ON o.id = oli.order_id
-- 必须先按订单ID排序,再按你定义的“首个”规则排序(比如OLI的创建时间)
ORDER BY o.id, oli.created_at ASC;

注意:DISTINCT ON后面的字段(这里是o.id)必须是ORDER BY子句的第一个字段,后面的排序字段决定了哪条OLI会被选为“首个”。

2. 使用窗口函数ROW_NUMBER()

如果需要更灵活的逻辑(比如过滤某些OLI后再取首个),窗口函数是更好的选择:

SELECT *
FROM (
    SELECT 
        o.*,
        oli.*,
        -- 按订单分组,给每个OLI编号,按创建时间升序排,首个就是1
        ROW_NUMBER() OVER (PARTITION BY o.id ORDER BY oli.created_at ASC) AS rn
    FROM orders o
    LEFT JOIN order_line_items oli ON o.id = oli.order_id
) AS subquery
WHERE rn = 1; -- 只保留每个订单的第一条OLI

这种方式适合复杂场景,比如你需要先过滤掉已取消的OLI,再取剩余的首个。


内容的提问来源于stack exchange,提问作者Tim Willis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:14:14