我正在寻找给定时间范围内存在多少分组间隙。
starting range: 2012-01-12 00:00:00 ending range: 2012-01-18 59:59:59
大致翻译为:
type 10 11 12 13 14 15 16 17 18 19 20 a |--========] a |==------] b |==============--] c |-----===========] d |--=====================------]
相同的数据按类型分组:
a |--========] |==------] b |==============--] c |-----===========] d |--=====================------]
导致:
type gap --------- a 1 (yes) b 1 (yes) c 1 (yes) d 0 (no)
最终…
SUM(gap) AS gaps ---------------- 3
更新以进行澄清:
每种类型的数据均以开始和结束时间戳记存储。例如:
id type start_datetime end_datetime -------------------------------------------------- 1 a 2012-01-11 00:00:00 2012-01-14 59:59:59 2 a 2012-01-18 00:00:00 2012-01-20 59:59:59 3 b 2012-01-14 00:00:00 2012-01-19 59:59:59 4 c 2012-01-10 00:00:00 2012-01-15 59:59:59 5 d 2012-01-11 00:00:00 2012-01-20 59:59:59
这是wildplasser回答的一种变体,它使用Windows而不是CTE。基于相同的测试夹具:
select ztype, count(*) as gaps from ( select ztype, datetime, sum(n) over(partition by ztype order by datetime asc) as level from ( select id, ztype, start_datetime as datetime, 1 as n from tmp.gaps union all select id, ztype, end_datetime, -1 from tmp.gaps union all select 0, ztype, '2012-01-12 00:00:00', 0 from (select distinct ztype from tmp.gaps) z union all select 0, ztype, '2012-01-19 00:00:00', 0 from (select distinct ztype from tmp.gaps) z ) x ) x where level = 0 and datetime >= '2012-01-12 00:00:00' and datetime < '2012-01-19 00:00:00' group by ztype ;
这是基于使用sum()作为窗口聚合,将1作为范围起点,将1减去范围终点,然后在目标范围内查找运行总和变为0的点。我必须做与wildplasser差不多的事情,添加一些额外的条目,这些条目在边界的端点处不做任何贡献,以便找到没有任何东西覆盖边界的组…
这似乎减少了测试数据的开销,但是我认为这可能很大程度上取决于表中没有太多数据要通过。进行一些重新排列(这将使其变得更难阅读),它可以仅对tmp.gaps进行两次完整扫描(其中一次只是获取不同的ztype)。