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

PostgreSQL如何按s_position排序聚合行且保持结果行数不变?

PostgreSQL按s_position排序聚合行且保持结果行数不变的解决方案

原查询语句:

SELECT p.*, po.product_options
    FROM product p
    LEFT JOIN  (
        SELECT po.p_id, 
               json_agg(
                  json_build_object('id', po.id, 'name', po.name, 'options', pom.option_name)) AS product_options
        FROM product_options po
        INNER JOIN (
          SELECT product_options_id, json_agg(option_name) as option_name
          FROM product_options_value
          GROUP BY product_options_id
          ) pom ON pom.product_options_id = po.id
        GROUP BY p_id
    ) po ON po.p_id = p.id
WHERE p.id = 1;

尝试对product_options表的行按s_position列排序时,出现报错:

ERROR: column "po.s_position" must appear in the GROUP BY clause or be used in an aggregate function

若将s_position加入GROUP BY子句,会得到2行结果,不符合预期的1行结果。

解决方案

PostgreSQL的json_agg聚合函数支持在内部指定排序规则,无需将s_position加入GROUP BY子句。只需在json_agg的参数后添加ORDER BY po.s_position,即可实现按s_position排序聚合行,同时保持原有分组逻辑(结果行数不变)。

修改后的查询语句:

SELECT p.*, po.product_options
    FROM product p
    LEFT JOIN  (
        SELECT po.p_id, 
               json_agg(
                  json_build_object('id', po.id, 'name', po.name, 'options', pom.option_name)
                  ORDER BY po.s_position) AS product_options -- 此处添加排序规则
        FROM product_options po
        INNER JOIN (
          SELECT product_options_id, json_agg(option_name) as option_name
          FROM product_options_value
          GROUP BY product_options_id
          ) pom ON pom.product_options_id = po.id
        GROUP BY p_id
    ) po ON po.p_id = p.id
WHERE p.id = 1;

原理说明

  • json_agg允许在聚合过程中对输入的行进行排序,排序字段不需要出现在GROUP BY中,因为它是聚合操作内部的排序逻辑,不会改变分组的依据(依然按p_id分组)。
  • 这样既满足了按s_position排序聚合行的需求,又保证每个p_id只返回一行聚合结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:32:41