活動時間重疊
一、概述
有這麼有一個需求:假如我有個網站,需要增加活動的功能。但是活動的時間不能有重疊,即一段時間內只能由一個活動。該如何實現功能了?
二、分析
由於增加活動一般都是後臺管理員來操作,而且不是頻繁,所以我把數據存到數據庫中,每次增加活動記錄,都現在數據庫中查詢,看是否存在活動時間衝突。每個活動都由一個開始時間和結束時間
三、實現方式
首先要明白一點,在數據庫中的活動都是不存在活動時間衝突的。
規定:未保留活動開始時間:s_time 未保留活動結束時間:e_time
已保留活動開始時間:r_s_time 已保留活動結束時間:r_e_time
- 取交集:
首先,根據活動開始時間篩選出 >= s_time的所有活動,記爲S1;根據活動開始時間篩選出 <= e_time的所有活動,記爲S2;然後對兩個數據集取交集S1 ^ S2,記爲S3。如果S3爲空,則不衝突,否則衝突。 - 高效解決方式(一條sql解決)
在這裏,我們先考慮存在活動衝突的三種情況:- s_time <= r_e_time && s_time >= r_s_time:未保留活動的開始時間在已保留活動時間範圍內,會有衝突。
- e_time <= r_e_time && e_time >= r_s_time:和上面條件類似。
- s_time < r_s_time && e_time > r_e_time:已保留活動的時間段包含在未保留活動的時間段類,會有衝突。
除了上面三種情況,那活動就保存到數據庫中了。
- s_time <= r_e_time && s_time >= r_s_time:未保留活動的開始時間在已保留活動時間範圍內,會有衝突。
select count(*) from activity
where (#{sTime} >= s_time and #{sTime} <= e_time)
OR (#{eTime} >= s_time and #{eTime} <= e_time)
OR (#{sTime} <= s_time and #{eTime} >= e_time)
count(*) > 0 存在衝突
四、總結
取交集的方式比較容易想到,但是sql實現起來比較複雜,mysql好像不支持交集原生方式,通過UNION來實現交集。對於這種類似的需求,以後還是多加分析,才能寫出高效代碼。