2015-12-22 80 views
3

我一直在想如何簡化這裏提出的問題。 Complex MySQL Query - Checking for overlapping DATE intervals檢查新的時間間隔是否重疊 - MySQL(或PHP)

在它的心臟,減去與DATES所有幻想魔術這僅僅是一個檢查重疊間隔的問題。在所有的日期都可以被認爲是數字,它可能會使邏輯更容易。想象一下如下表:

Schedules 
schedule_id  |  start  |  end 
1    |  1  |  3 
2    |  4  |  7     
3    |  8  |  13 
4    |  15  |  16 
5    |  18  |  24 
6    |  25  |  28 

我試圖插入一個新的區間,使得[A,B]不與任何其他區間重疊。考慮因素:

  • 是的,我可以將整個表格拉到一個數組中,並對其進行O(N)搜索。那很無聊。
  • 我更喜歡在MySQL中這樣做,所以我不必每次都拉下可以是任意大表的表。

看到下圖。這代表了可以插入和不能插入的範圍。 http://i.stack.imgur.com/jE59w.png

+0

你想插入什麼間隔?如果你只想要任何一個,那麼選擇最大的'end'值,並添加一個用於開始。然後你可以讓'end'有更大的值。 –

+0

@GordonLinoff - 我想插入一個任意的時間間隔,以便與任何其他時間間隔沒有衝突。間隔可以是任意長度。根據我發佈的圖片,頂部的小間隔將是「有效的」,因爲它不會與底部發生衝突,因爲我試圖表示所有可能的衝突。基本上「我的新時間間隔是否存在(或包含在)存在的任何事物中?是否有任何事情進入(或包含在)我的新時間間隔中?」 – SWEp7WasMeh

+0

'SELECT * FROM Schedules WHERE start <= 17 AND end> = 16'會返回您提出的插入衝突的所有間隔。 – eggyal

回答

1

使用如下因素的縮寫:

  • [舊]:=現有範圍
  • [新]:=插入範圍
  • OS:=(舊)existing_range.start
  • OE:=(舊)existing_range.end
  • NS:=(新)insertion_range.start
  • NE:=(new)insertion_range。結束

兩個範圍(新舊)的overlaping的條件是:(OS < NE) AND (OE > NS)

雖然解決方案可能是不平凡的,它不是很難得到有:

沒有overlaping如果新的範圍是完全地之前或現有的範圍後:[new] <= [old] OR [old] <= [new]那意思是說:

(NE <= OS) OR (OE <= NS) 

談判這一說法,我們得到鄰條件verlaping:

!((NE <= OS) OR (OE <= NS)) 

現在使用De Morgan's law,我們可以把它寫成

!(NE <= OS) AND !(OE <= NS) 

這相當於

(NE > OS) AND (OE > NS) 

至極可以rewriten爲

(OS < NE) AND (OE > NS) 

現在我們可以找到所有的ov erlaping範圍使用

SELECT o.* 
FROM Schedules o 
WHERE o.start < :new_end 
    AND o.end > :new_start 
0

您可以短語插入爲:

insert into schedules(start, end) 
    select s, e 
    from (select $start s, $end as e) t 
    where not exists (select 1 
         from schedules s2 
         where s.start <= t.end and s.end >= t.start 
        ); 

這隻會插入值,如果它不與表中的現有行重疊。

相關問題