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

SQL查询需求:相同phoneNumber仅返首行,NULL行全部保留

解决相同phoneNumber仅返回首行、NULL行全部保留的查询需求

我来帮你搞定这个问题——你遇到的情况确实是DISTINCT的局限性:SQL标准里所有NULL会被视为相同值,所以DISTINCT只能返回一条NULL行,完全不符合你的需求。下面用窗口函数的方案就能完美解决,而且适配绝大多数主流数据库。

核心思路

用ROW_NUMBER()窗口函数做分组编号:

  • 对于非NULL的phoneNumber,按相同值分组,给每组内的行按你指定的规则(比如创建时间、主键顺序)编号,只保留编号为1的行(也就是每组的第一行)。
  • 对于NULL的phoneNumber,给每一行分配一个唯一的分组依据(比如主键、临时UUID),让每一行单独成为一个分组,这样编号自然都是1,所有NULL行都会被保留。

通用示例代码(推荐用主键做唯一标识)

假设你的表名为your_table,主键是id,需要保留的字段包括phoneNumber、username、create_time等:

SELECT id, phoneNumber, username, create_time -- 明确列出需要的字段,避免用*
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER (
            PARTITION BY CASE 
                            WHEN phoneNumber IS NOT NULL THEN phoneNumber 
                            ELSE id -- 用主键作为NULL行的唯一分组依据
                         END 
            ORDER BY create_time ASC -- 指定排序规则,确定“第一行”的顺序(比如最早创建的行)
        ) AS row_num
    FROM your_table
) sub_query
WHERE row_num = 1;

不同数据库的适配方案

如果你的表没有主键,或者需要更灵活的实现,可以根据数据库类型调整:

  • MySQL:用UUID()生成临时唯一值
SELECT phoneNumber, username, create_time
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER (
            PARTITION BY CASE 
                            WHEN phoneNumber IS NOT NULL THEN phoneNumber 
                            ELSE UUID() 
                         END 
            ORDER BY id ASC
        ) AS row_num
    FROM your_table
) t
WHERE row_num = 1;
  • PostgreSQL:用ctid(行物理位置标识)代替主键
SELECT phoneNumber, username, create_time
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER (
            PARTITION BY CASE 
                            WHEN phoneNumber IS NOT NULL THEN phoneNumber 
                            ELSE ctid 
                         END 
            ORDER BY created_at ASC
        ) AS row_num
    FROM your_table
) t
WHERE row_num = 1;
  • SQL Server:用NEWID()生成唯一值
SELECT phoneNumber, username, create_time
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER (
            PARTITION BY CASE 
                            WHEN phoneNumber IS NOT NULL THEN phoneNumber 
                            ELSE NEWID() 
                         END 
            ORDER BY id ASC
        ) AS row_num
    FROM your_table
) t
WHERE row_num = 1;

关键注意事项

  • 一定要指定ORDER BY子句:如果不指定,数据库会随机返回分组内的某一行,“第一行”的结果完全不可控。
  • 生产环境避免用SELECT *:明确列出需要的字段,既提升查询效率,也能避免后续表结构变更带来的意外问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:55:53