按guid分组查询记录:指定日期取最大日期,无则取下一可用日最小记录
针对DATAS表的分组查询SQL实现
首先假设表结构如下(若实际结构有差异,可按需调整字段):
CREATE TABLE DATAS ( guid VARCHAR(36) NOT NULL, startdate DATE NOT NULL, -- 其他业务字段示例 col1 VARCHAR(50), col2 INT, PRIMARY KEY (guid, startdate) -- 假设组合主键,避免同guid同日期的重复记录 );
需求逻辑拆解
对每个guid,按以下规则筛选单条记录:
- 若存在
startdate等于指定日期(假设参数为@target_date)的记录,取该日期下startdate最大的记录(因日期相同,实际为该日期的任意一条,若有重复可结合其他字段排序); - 若指定日期无对应记录,取大于指定日期的最早可用日期中
startdate最小的记录(即该最早日期的记录)。
最终SQL实现(支持窗口函数的数据库:MySQL 8.0+/PostgreSQL/SQL Server等)
WITH ranked_records AS ( SELECT *, -- 标记记录优先级:指定日期记录优先级最高,后续日期次之 CASE WHEN startdate = @target_date THEN 0 WHEN startdate > @target_date THEN 1 ELSE 2 -- 排除早于指定日期的非目标记录 END AS priority, -- 按guid分组,按优先级+规则排序,生成唯一序号 ROW_NUMBER() OVER ( PARTITION BY guid ORDER BY priority, CASE WHEN startdate = @target_date THEN startdate END DESC, startdate ASC ) AS rn FROM DATAS WHERE startdate >= @target_date -- 仅保留符合规则的候选记录 ) SELECT guid, startdate, col1, col2 -- 替换为实际需要查询的字段 FROM ranked_records WHERE rn = 1;
逻辑说明
- CTE子查询:
- 通过
CASE给记录划分优先级,指定日期的记录优先级为0,后续日期为1,早于指定日期的标记为2(后续过滤); - 使用
ROW_NUMBER()按guid分组排序:先按优先级排序,同优先级内,指定日期组按startdate降序(兼容可能的时间精度差异),后续日期组按startdate升序(取最早的后续日期)。
- 通过
- 主查询:筛选每个
guid中序号为1的记录,即为符合需求的结果。
兼容无窗口函数的数据库(如MySQL 5.x)
SELECT d1.* FROM DATAS d1 WHERE (d1.guid, d1.startdate) IN ( SELECT guid, CASE -- 优先匹配指定日期 WHEN EXISTS (SELECT 1 FROM DATAS d2 WHERE d2.guid = d.guid AND d2.startdate = @target_date) THEN @target_date -- 无匹配时取后续最早日期 ELSE (SELECT MIN(startdate) FROM DATAS d3 WHERE d3.guid = d.guid AND d3.startdate > @target_date) END AS target_startdate FROM (SELECT DISTINCT guid FROM DATAS) d ) -- 若同guid在目标日期有多条记录,取startdate最大的 AND d1.startdate = ( SELECT MAX(startdate) FROM DATAS d4 WHERE d4.guid = d1.guid AND d4.startdate = d1.startdate );
自定义调整提示
- 若“指定日期存在对应记录”指
startdate <= @target_date(而非严格等于),可将优先级0的条件改为startdate <= @target_date,并在排序时取该范围内最大的startdate; - 若表包含
enddate(记录生效周期),需添加enddate >= @target_date的条件判断“指定日期是否有有效记录”,可根据业务场景调整。
内容的提问来源于stack exchange,提问作者user3625533
相关产品推荐
相关产品推荐

