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

如何从各列选取非NULL的TOP 1值?同ID多行合并为一行

解决同ID多行合并为单行(取非NULL值)的方案

嘿,这个需求我经常碰到,核心就是把同ID的多条记录聚合起来,提取每列的非NULL值——不管是任意非NULL还是按顺序的TOP1,都有对应的解决方案,而且完全不用WHERE子句。下面分几种主流数据库给你具体实现:

基础通用方案(不关心非NULL值顺序)

如果你的需求只是“只要列有非NULL值就展示,全NULL则返回NULL”,不关心取哪一个非NULL值,那么用MAX()或MIN()聚合函数是最简单高效的,因为它们会自动忽略NULL值,对每个ID分组后返回该列的非NULL值(如果有多个,返回最大/最小的,但满足“非NULL就展示”的要求)。

MySQL/MariaDB、PostgreSQL、SQL Server 通用代码

SELECT 
    id,
    MAX(column1) AS column1,
    MAX(column2) AS column2,
    MAX(column3) AS column3
    -- 继续添加你需要的所有列
FROM your_table
GROUP BY id;

把your_table换成你的表名,column1/column2换成实际要提取的列即可

按指定顺序取TOP1非NULL值

如果需要按特定逻辑(比如创建时间最早、更新时间最晚)取第一个出现的非NULL值,就需要用到窗口函数,不同数据库的语法略有差异:

MySQL 8.0.22+ 版本

MySQL 8.0.22及以上支持IGNORE NULLS关键字,可以直接跳过NULL值取第一个非NULL:

SELECT DISTINCT
    id,
    FIRST_VALUE(column1 IGNORE NULLS) OVER (PARTITION BY id ORDER BY create_time ASC) AS column1,
    FIRST_VALUE(column2 IGNORE NULLS) OVER (PARTITION BY id ORDER BY create_time ASC) AS column2
FROM your_table;

create_time换成你用来排序的字段,ASC是升序(最早的在前),DESC是降序(最晚的在前)

PostgreSQL

PostgreSQL原生支持IGNORE NULLS,语法更简洁:

SELECT DISTINCT
    id,
    FIRST_VALUE(column1) OVER (PARTITION BY id ORDER BY create_time ASC IGNORE NULLS) AS column1,
    FIRST_VALUE(column2) OVER (PARTITION BY id ORDER BY create_time ASC IGNORE NULLS) AS column2
FROM your_table;

SQL Server 2022+ 版本

SQL Server 2022开始支持IGNORE NULLS,用法如下:

SELECT DISTINCT
    id,
    FIRST_VALUE(column1) OVER (PARTITION BY id ORDER BY create_time ASC ROWS UNBOUNDED PRECEDING IGNORE NULLS) AS column1,
    FIRST_VALUE(column2) OVER (PARTITION BY id ORDER BY create_time ASC ROWS UNBOUNDED PRECEDING IGNORE NULLS) AS column2
FROM your_table;

旧版SQL Server(无IGNORE NULLS支持)

如果是2022之前的版本,可以用ROW_NUMBER()来优先排序非NULL行,再提取第一个值:

WITH ranked_data AS (
    SELECT 
        id,
        column1,
        column2,
        -- 给column1的非NULL行排前面,再按时间排序
        ROW_NUMBER() OVER (PARTITION BY id ORDER BY CASE WHEN column1 IS NOT NULL THEN 0 ELSE 1 END, create_time ASC) AS rn1,
        -- 同理处理column2
        ROW_NUMBER() OVER (PARTITION BY id ORDER BY CASE WHEN column2 IS NOT NULL THEN 0 ELSE 1 END, create_time ASC) AS rn2
    FROM your_table
)
SELECT 
    id,
    MAX(CASE WHEN rn1 = 1 THEN column1 END) AS column1,
    MAX(CASE WHEN rn2 = 1 THEN column2 END) AS column2
FROM ranked_data
GROUP BY id;

关键说明

  • 所有方案都不需要WHERE子句,直接处理全表数据,你之前用WHERE只是测试缩小范围,现在去掉即可。
  • 如果你的表数据量很大,优先用分组聚合的方案(MAX()/MIN()),性能比窗口函数更好;如果有顺序要求,再用窗口函数版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:24:31