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

如何将PostgreSQL多行查询结果转换为单行多列?

需求可行,两种实现方法如下

方法一:条件聚合(新手友好,无需额外扩展)

这种方法通过CASE WHEN结合聚合函数,把不同座位等级的占比结果映射到单独的列中,逻辑直观,适合SQL新手理解。

完整SQL代码

SELECT
  datum,
  naam,
  -- 根据实际seatrank值调整条件,对应第一个座位等级的占比
  MAX(CASE WHEN seatrank = 1 THEN rangen END) AS rangen_rank1,
  -- 对应第二个座位等级
  MAX(CASE WHEN seatrank = 2 THEN rangen END) AS rangen_rank2,
  -- 对应第三个座位等级
  MAX(CASE WHEN seatrank = 3 THEN rangen END) AS rangen_rank3,
  -- 对应第四个座位等级
  MAX(CASE WHEN seatrank = 4 THEN rangen END) AS rangen_rank4
FROM (
  SELECT
    sr.namenl rang,
    COUNT(CASE WHEN t.currentstatus IS NULL THEN '1' END) AS beschikbaar,
    COUNT(CASE WHEN t.currentstatus = 101 THEN '2' END) AS verkocht,
    COALESCE(e.namenl) || ' ' || COALESCE(e.subtitlenl,'') naam,
    e.startts datum,
    sr.id seatrank,
    -- 提前在子查询计算占比,简化外层逻辑
    TO_CHAR(verkocht::NUMERIC/(verkocht+beschikbaar)*100, 'fm00D00%') rangen
  FROM tm.ticket t
  INNER JOIN tm.tickettype tt ON tt.id = t.tickettypeid
  INNER JOIN tm.event e ON e.id = tt.eventid
  INNER JOIN tm.seatrank sr ON sr.id = tt.seatrankid
  WHERE e.id = 28744
  GROUP BY 1,4,5,6
) sq1
GROUP BY datum, naam;

关键说明

  • 你需要根据实际的seatrank值(即座位等级的ID)修改CASE WHEN里的判断条件,比如如果你的四个座位等级ID是5、6、7、8,就把seatrank = 1改成对应的数字。
  • 使用MAX()是因为每个datum+naam+seatrank组合只有一行数据,MAX只是用来提取唯一的占比值,换成MIN()也能达到同样效果。

方法二:PostgreSQL专用交叉表(crosstab)

如果你的PostgreSQL环境允许启用扩展,crosstab函数是更简洁的转列方式,适合固定数量类别的场景。

步骤1:启用tablefunc扩展(仅需执行一次)

CREATE EXTENSION IF NOT EXISTS tablefunc;

步骤2:编写交叉表查询

SELECT * FROM crosstab(
  -- 源查询:返回分组键(datum、naam)、类别键(seatrank)、值(rangen)
  'SELECT
     datum,
     naam,
     seatrank,
     rangen
   FROM (
     SELECT
       sr.namenl rang,
       COUNT(CASE WHEN t.currentstatus IS NULL THEN ''1'' END) AS beschikbaar,
       COUNT(CASE WHEN t.currentstatus = 101 THEN ''2'' END) AS verkocht,
       COALESCE(e.namenl) || '' '' || COALESCE(e.subtitlenl,'''') naam,
       e.startts datum,
       sr.id seatrank,
       TO_CHAR(verkocht::NUMERIC/(verkocht+beschikbaar)*100, ''fm00D00%'') rangen
     FROM tm.ticket t
     INNER JOIN tm.tickettype tt ON tt.id = t.tickettypeid
     INNER JOIN tm.event e ON e.id = tt.eventid
     INNER JOIN tm.seatrank sr ON sr.id = tt.seatrankid
     WHERE e.id = 28744
     GROUP BY 1,4,5,6
   ) sq1
   ORDER BY 1,2,3',
  -- 指定要生成列的类别值(自动获取当前事件的所有座位等级ID)
  'SELECT DISTINCT seatrank 
   FROM tm.seatrank 
   WHERE id IN (SELECT seatrankid FROM tm.tickettype WHERE eventid=28744) 
   ORDER BY id'
) AS ct(
  datum TIMESTAMP,
  naam TEXT,
  rangen_rank1 TEXT,
  rangen_rank2 TEXT,
  rangen_rank3 TEXT,
  rangen_rank4 TEXT
);

关键说明

  • 源查询必须严格按照「分组键 → 类别键 → 目标值」的顺序返回列。
  • 结果表定义AS ct(...)里的列名和类型要和实际数据匹配,列数要等于分组键数量加类别数量(这里是2个分组键+4个类别=6列)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:31:12