2010-05-05 164 views
4

我有一個表,其中每行都有一個開始和結束日期時間。這些可以是任意短或長的跨度。SQL中的日期範圍交集

我想查詢具有兩個開始和停止日期時間的所有行的交集的持續時間。

你怎麼能在MySQL中做到這一點?

或者您是否必須選擇與查詢開始和結束時間相交的行,然後計算每行的實際重疊並將其與客戶端相加?


舉個例子,使用毫秒這樣可以很清楚:

的某些行:

ROW START STOP 
1 1010 1240 
2  950 1040 
3 1120 1121 

而且我們想知道的總和時,這些行分別爲1030和1100之間。

允許計算各行的重疊:

ROW INTERSECTION 
1 70 
2 10 
3  0 

所以在這個例子中的總和是80.

+3

我很難理解你的問題。你能否舉例說明一下。 – lexu 2010-05-05 07:30:45

+0

像1-10,2-9,3-8這樣的重疊的總和是多少? – aioobe 2010-05-05 07:39:56

+0

@Will - 如果我正確讀了你的話,你在示例#1中的交集不應該是30;交叉點((1010,1240),(1030,1100))= 70 – Unreason 2010-05-05 08:46:56

回答

5

如果你的榜樣應該說70的第一行中,然後

假設@range_start和@range_end作爲你的條件paramters:使用greatest /最少,date functions你應該能夠

SELECT SUM(LEAST(@range_end, stop) - GREATEST(@range_start, start)) 
FROM Table 
WHERE @range_start < stop AND @range_end > start 

得到你需要的日期類型直接操作。

1

我擔心你的運氣不好。

由於您不知道您將「累積相交」的行數,因此您需要遞歸解決方案或聚合運算符。

您需要的聚合運算符是沒有選擇的,因爲SQL沒有它應該操作的數據類型(該類型是間隔類型,如「時間數據和關係模型」中所述)。

遞歸解決方案可能是可能的,但它可能很難編寫,難以向其他程序員讀取,並且優化程序是否可以將該查詢轉換爲最佳數據訪問策略也是個問題。

或者我誤解了你的問題。

1

如果你知道你有最大的時間,那麼有一個相當有趣的解決方案。創建一個包含所有數字的表格,從一個表格到最長時間。

millisecond 
----------- 
1 
2 
3 
... 
1240 

稱它爲time_dimension(這種技術通常在數據倉庫維度建模使用。)

那麼這個:

SELECT 
    COUNT(*) 
FROM 
    your_data 
    INNER JOIN time_dimension ON time_dimension.millisecond BETWEEN your_data.start AND your_data.stop 
WHERE 
    time_dimension.millisecond BETWEEN 1030 AND 1100 

...會給你1030到1100之間的總運行時間毫秒數。

當然,你是否可以使用這種技術取決於你是否可以安全地預測數據中的最大毫秒數。

正如我所說,這通常用於數據倉庫;它非常適合於某些類型的問題 - 例如,我已經將它用於保險系統,其中需要兩個日期之間的總天數,並且數據的整個日期範圍很容易估算(來自最早的出生日期至未來幾年的日期,超過任何正在出售的政策的結束日期。)

可能不適合你,但我想它值得作爲一種有趣的技術分享!

0

在您添加示例之後,顯然確實我誤解了您的問題。

你不是「累積相交的行」。

,將帶給你一個解決方案的步驟是:

相交的每一行的起點和終點與給定的起點和終點。

SELECT(CASE STARTDATE < givenstartdate:givenstartdate,CASE STARTDATE> = givenstartdate:開始日期)爲retainedstartdate,(同樣爲結束日期),其retainedenddate這應該使用的樣式CASE表達式或自然的東西,什麼是可行FROM ...根據需要照顧nulls和那種東西。

使用retainstartdate和retainedenddate,使用日期函數來計算保留區間的長度(這是您的行與給定時間區段的重疊)。

選擇這些的SUM()。