想法是将时间分成不同的时间段,并将它们作为具有指定粒度的位值保存。
0
- 在一个时间段内没有人签到
1
- 在一个时间段内有人签到
假设粒度为1小时,时间段为1天。
- 000000000000000000000000 表示这一天没有人签到
- 000000000000000000000110 表示在21点至23点之间有人签到
- 000000000000011111000000 表示在13点至18点之间有人签到
- 000000000000000111111100 表示在15点至22点之间有人签到
然后我们对范围内每个值进行二进制OR运算,就得到了我们的答案。
这可以在线性时间内完成。以下是来自Oracle的示例,但很容易转换为PostgreSQL。
with rec (checkin, checkout)
as ( select 13, 18 from dual
union all
select 15, 22 from dual
union all
select 21, 23 from dual )
,spanempty ( empt)
as ( select '000000000000000000000000' from dual) ,
spanfull( full)
as ( select '111111111111111111111111' from dual)
, bookingbin( binbook) as ( select substr(empt, 1, checkin) ||
substr(full, checkin, checkout-checkin) ||
substr(empt, checkout, 24-checkout)
from rec
cross join spanempty
cross join spanfull ),
bookingInt (rn, intbook) as
( select rownum, bin2dec(binbook) from bookingbin),
bitAndSum (bitAndSumm) as (
select sum(bitand(b1.intbook, b2.intbook)) from bookingInt b1
join bookingInt b2
on b1.rn = b2.rn -1 ) ,
SumAll (sumall) as (
select sum(bin2dec(binbook)) from bookingBin )
select lpad(dec2bin(sumall - bitAndSumm), 24, '0')
from SumAll, bitAndSum
结果:
000000000000011111111110
\d tbl
命令获取的信息)以及一些样本数据。谢谢。 - Erwin Brandstetter