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

PostgreSQL中按分析ID拆分2019/2020年订单数至列的查询问题

解决按分析项ID单行展示两年订单数的SQL问题

问题背景

现有两张表:

  • analysis(an_id, an_name, an_cost, an_price, an_group)
  • orders(ord_id, ord_datetime, ord_an)—— 分析项的销售订单数据

需求:为每个an_id展示2019年和2020年的订单数量,要求每行对应一个an_id,同时显示两年的订单数。原查询因分组逻辑问题,输出为每个an_id分两行显示(一行对应2019年,一行对应2020年),不符合需求。

原查询问题分析

原查询的核心问题是GROUP BY子句同时包含了year和an_id,导致每个an_id会按年份拆分为独立分组,最终输出两行数据。此外,CASE WHEN放在COUNT外部,仅对当前分组的年份计数,另一年份只能返回0。

修正方案:条件聚合

使用条件聚合(将CASE WHEN嵌套在聚合函数内部),同时仅按an_id分组,即可实现单行展示两年数据的需求。

方案1:基于原CTE修改

WITH helper AS (
    SELECT a.an_id, 
           o.ord_id, 
           EXTRACT(year from o.ord_datetime) AS year
    FROM analysis a 
    INNER JOIN orders o ON o.ord_an = a.an_id
    WHERE EXTRACT(year FROM o.ord_datetime) IN (2019, 2020)
)
SELECT an_id,
       -- 仅统计2019年的订单数,不满足条件的返回NULL,COUNT自动忽略
       COUNT(CASE WHEN year = 2019 THEN ord_id END) AS year2019,
       COUNT(CASE WHEN year = 2020 THEN ord_id END) AS year2020
FROM helper
GROUP BY an_id -- 仅按an_id分组,确保每个an_id一行
ORDER BY an_id;

方案2:简化为单查询(推荐)

直接在主查询中完成条件聚合,无需CTE,同时改用LEFT JOIN确保无订单的an_id也能显示(若不需要可换回INNER JOIN):

SELECT a.an_id,
       COUNT(CASE WHEN EXTRACT(year FROM o.ord_datetime) = 2019 THEN o.ord_id END) AS year2019,
       COUNT(CASE WHEN EXTRACT(year FROM o.ord_datetime) = 2020 THEN o.ord_id END) AS year2020
FROM analysis a
LEFT JOIN orders o 
    ON o.ord_an = a.an_id 
    AND EXTRACT(year FROM o.ord_datetime) IN (2019, 2020)
GROUP BY a.an_id
ORDER BY a.an_id;

原理说明

  • 条件聚合中,CASE WHEN仅在满足年份条件时返回ord_id,否则返回NULL;
  • COUNT()函数会自动忽略NULL值,因此只会统计对应年份的有效订单数;
  • 仅按an_id分组,确保每个an_id生成唯一一行数据,同时展示两年的订单统计结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 05:03:27