如何在SQL中按分组删除Start值非最小的观测记录?
按分组保留最小Start值记录的SQL解决方案
原始数据集
| Group | Start | End |
|---|---|---|
| A | 2021-01-01 | 2021-04-05 |
| A | 2021-01-01 | 2021-06-05 |
| A | 2021-03-01 | 2021-06-05 |
| B | 2021-06-13 | 2021-08-05 |
| B | 2021-06-13 | 2021-09-05 |
| B | 2021-07-01 | 2021-09-05 |
| C | 2021-10-07 | 2021-10-17 |
| C | 2021-10-07 | 2021-11-15 |
| C | 2021-11-12 | 2021-11-15 |
期望结果
按分组保留Start值为组内最小值的所有记录,删除其余记录:
| Group | Start | End |
|---|---|---|
| A | 2021-01-01 | 2021-04-05 |
| A | 2021-01-01 | 2021-06-05 |
| B | 2021-06-13 | 2021-08-05 |
| B | 2021-06-13 | 2021-09-05 |
| C | 2021-10-07 | 2021-10-17 |
| C | 2021-10-07 | 2021-11-15 |
问题说明
直接在WHERE子句中使用聚合函数MIN(Start)会报错,因为WHERE是行级过滤逻辑,无法直接引用针对分组计算的聚合结果,你尝试的代码如下:
Delete from #df1 where start != min(start)
解决方案
以下三种方法均可实现需求,根据你的SQL环境选择合适的方案:
方法1:关联子查询匹配组内最小Start值
通过子查询预先计算每组的最小Start值,再关联原表删除不符合条件的记录:
DELETE t FROM #df1 t WHERE t.Start != ( SELECT MIN(Start) FROM #df1 WHERE [Group] = t.[Group] )
注意:
Group是SQL保留关键字,需用方括号[Group]包裹避免语法错误。
方法2:使用窗口函数标记组内最小Start值
利用窗口函数MIN() OVER (PARTITION BY ...)为每行标记对应分组的最小Start值,再过滤删除不符合条件的记录:
WITH MinStartCTE AS ( SELECT *, MIN(Start) OVER (PARTITION BY [Group]) AS GroupMinStart FROM #df1 ) DELETE FROM MinStartCTE WHERE Start != GroupMinStart
方法3:通过JOIN筛选需删除的记录
先分组计算每组最小Start值,再通过左连接找出不在保留范围内的记录并删除:
DELETE t FROM #df1 t LEFT JOIN ( SELECT [Group], MIN(Start) AS MinStart FROM #df1 GROUP BY [Group] ) g ON t.[Group] = g.[Group] AND t.Start = g.MinStart WHERE g.MinStart IS NULL
注意事项
- 执行删除操作前,建议先将
DELETE替换为SELECT *,验证待删除的记录是否符合预期,避免误删数据。 - 确保临时表
#df1在当前会话中存在,且具备删除权限。
内容的提问来源于stack exchange,提问作者user17582908
相关产品推荐
相关产品推荐

