如何在SQL Server中筛选并排除完全被包含的日期范围数据?
我来帮你搞定这个日期范围过滤的需求~先把你提供的map表数据整理成更直观的表格:
原始map表数据
| sed | code | id | startdate | enddate |
|---|---|---|---|---|
| 101 | 1019 | A | 2002-12-02 | 2009-11-17 |
| 101 | 1019 | B | 1986-01-02 | 2009-11-04 |
| 101 | 1019 | C | 2009-07-01 | 2009-11-17 |
| 101 | 1019 | C | 2002-12-02 | 2009-06-30 |
| 101 | 1019 | D | 1986-01-03 | 2009-11-17 |
| 101 | 1019 | E | 2007-10-15 | 2009-11-17 |
| 101 | 1019 | E | 1992-01-31 | 1999-08-30 |
| 101 | 1019 | F | 2007-11-26 | 2009-11-05 |
| 101 | 1019 | F | 2007-09-05 | 2007-11-22 |
| 101 | 1019 | F | 2007-07-06 | 2007-09-03 |
你的需求是:排除那些被同组(sed和code相同)内其他行完全包含日期范围的记录,也就是只保留“没有任何其他行能把它的日期范围全包住”的行。
可行的SQL查询方案
用NOT EXISTS子查询就能精准实现这个逻辑,代码如下:
SELECT m1.* FROM map m1 WHERE NOT EXISTS ( SELECT 1 FROM map m2 -- 限定同一sed和code分组 WHERE m2.sed = m1.sed AND m2.code = m1.code -- m2的日期范围完全包含m1的 AND m2.startdate <= m1.startdate AND m2.enddate >= m1.enddate -- 排除自己和自己比较的情况(避免误判相同的行) AND NOT ( m2.id = m1.id AND m2.startdate = m1.startdate AND m2.enddate = m1.enddate ) );
逻辑解释
- 外层查询遍历
map表的每一行(记为m1) - 内层子查询检查:在同一
sed和code的分组里,是否存在另一行(记为m2),满足m2的开始日期更早、结束日期更晚,而且m2不是m1本身 - 如果不存在这样的
m2,就保留m1这条记录;如果存在,就排除它
结果验证
按照你的数据,最终会保留的行是:
- B行:它的开始日期(1986-01-02)比D行的更早,没有任何行能完全包含它
- D行:它的日期范围是最宽的,没有其他行能包含它
其他行都会因为被D行(或其他更宽的行)完全包含而被排除。
另外,如果你的表有唯一主键(比如自增的row_id),可以把最后那个排除自身的条件换成m2.row_id != m1.row_id,这样会更简洁准确。
内容的提问来源于stack exchange,提问作者koala




