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

PostgreSQL实现客户手机号行转列,解决单号码重复显示问题

问题描述

在Azure Data Studio中使用PostgreSQL设计客户信息数据库,客户最多可拥有两个不同手机号。执行SELECT *查询得到如下多行结果:

Name  |  Number
James |   12344532
James  |  23232422

期望将客户的两个手机号合并到同一行展示,格式如下(单个手机号的客户第二个号码字段留空):

Name  |   Number1  | Number2
James     12344532   23232422
John      32443322
Jude      12121212   23232422

尝试执行以下SQL语句:

SELECT name.name,
min(details.number) AS number1,
max(details.number) AS number2
FROM name
JOIN details
ON name.id=details.id
GROUP BY name.name

但结果中仅有一个手机号的客户,两个号码字段会重复显示该号码:

Name  |   Number1  | Number2
James     12344532   23232422
John      32443322   32443322
Jude      12121212   23232422
解决方案

问题出在MIN()和MAX()聚合函数上:当客户只有一个手机号时,这两个函数返回的是同一个值,导致两个字段重复。可以通过窗口函数+条件聚合的方式解决,让第二个号码字段在无数据时返回NULL(展示为空)。

方法1:使用ROW_NUMBER()窗口函数+CASE条件

SELECT 
    n.name,
    MAX(CASE WHEN rn = 1 THEN d.number END) AS number1,
    MAX(CASE WHEN rn = 2 THEN d.number END) AS number2
FROM name n
JOIN (
    -- 给每个客户的手机号按ID分组编号(1、2)
    SELECT 
        id,
        number,
        ROW_NUMBER() OVER (PARTITION BY id ORDER BY number) AS rn
    FROM details
) d ON n.id = d.id
GROUP BY n.name;

方法2:使用PostgreSQL专属的FILTER子句(更简洁)

SELECT 
    n.name,
    MAX(d.number) FILTER (WHERE rn = 1) AS number1,
    MAX(d.number) FILTER (WHERE rn = 2) AS number2
FROM name n
JOIN (
    SELECT 
        id,
        number,
        ROW_NUMBER() OVER (PARTITION BY id ORDER BY number) AS rn
    FROM details
) d ON n.id = d.id
GROUP BY n.name;

原理说明

  1. 子查询中通过ROW_NUMBER()给每个客户的手机号分配序号(PARTITION BY id按客户分组,ORDER BY number按手机号排序),序号为1和2。
  2. 外层聚合时,仅提取序号为1的手机号作为number1,序号为2的作为number2;若客户只有一个手机号,序号2不存在,对应字段会返回NULL(展示为空),避免重复。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:15:34