获取每月1日各ID对应col2列最新值的SQL查询需求
解决方案:获取每个ID每月1日对应的最新col2值
看起来你需要的是每个ID在指定月份(2019年1-4月)的每月1日,对应到该日期之前最后一次修改的col2值,没有修改记录的话返回NULL。我来给你拆解思路并提供可行的SQL方案:
核心思路
- 先生成你需要的目标日期范围:2019年1月1日到4月1日的每月第一天。
- 把所有唯一ID和这些日期做组合,确保每个ID都能覆盖所有目标月份。
- 对每个「ID+每月1日」的组合,找到该日期之前(不含该日期之后)最新的修改记录,提取对应的col2;如果没有符合条件的记录,返回NULL。
通用SQL实现(以PostgreSQL为例)
-- 步骤1:生成目标月份的第一天 WITH target_dates AS ( SELECT DATE '2019-01-01' AS month_start UNION ALL SELECT (month_start + INTERVAL '1 month')::DATE FROM target_dates WHERE month_start < DATE '2019-04-01' ), -- 步骤2:生成所有ID和目标日期的组合 all_id_month AS ( SELECT DISTINCT t.id, d.month_start FROM your_table t CROSS JOIN target_dates d ) -- 步骤3:查询每个组合对应的最新col2值 SELECT aim.id, aim.month_start AS "col2(first day of every month)", -- 子查询:找到当前ID在month_start之前最新的修改记录 (SELECT col2 FROM your_table t WHERE t.id = aim.id AND t.modified <= aim.month_start ORDER BY t.modified DESC LIMIT 1) AS col4 FROM all_id_month aim ORDER BY aim.id, aim.month_start;
代码解释
target_dates:用递归CTE生成你需要的4个月份的第一天,如果你需要扩展到更多月份,只需要修改WHERE条件里的日期即可。all_id_month:通过CROSS JOIN把每个唯一ID和所有目标日期组合,保证不会漏掉任何ID的任何月份。- 子查询部分:对每个「ID+每月1日」,筛选出该日期之前的所有修改记录,按修改时间倒序排列后取第一条,就是我们要的最新值;如果没有符合条件的记录,子查询返回NULL,正好符合需求。
不同数据库的适配调整
如果你的数据库不是PostgreSQL,只需要调整日期生成和语法细节:
- MySQL 8+:递归CTE支持,日期计算用
DATE_ADD(month_start, INTERVAL 1 MONTH),子查询语法一致。 - Oracle:用
CONNECT BY生成日期,比如:SELECT ADD_MONTHS(DATE '2019-01-01', LEVEL-1) AS month_start FROM dual CONNECT BY LEVEL <=4 - SQL Server:日期计算用
DATEADD(month, 1, month_start),递归CTE语法类似。
验证结果
这个查询完全符合你给出的输出要求:
- ID1的1月1日:没有早于2019-01-01的修改记录,返回NULL;
- ID2的3月1日:3月2日的blue是在3月1日之后,所以取最近的1月12日的green;
- ID3的1月1日:取2018年12月12日的red,以此类推。
内容的提问来源于stack exchange,提问作者Gaurav singh
相关产品推荐
相关产品推荐

