假設我有一個包含流媒體連接信息的表。在這張表中,我有一個開始時間和結束時間,當連接開始時,然後關閉。查詢一天內兩次之間的時間
表:日誌
- ID(INT,PK,AUTO_INCREMENT)
- 開始時間(DATETIME)
- 結束時間(DATETIME)
我希望能夠運行一個查詢這將增加一天中建立連接的總時間。這是在一天之內連接明顯:
SELECT
SUM(
TIME_TO_SEC(
TIMEDIFF(`EndTime`, `StartTime`)
)
)
WHERE (`StartTime` BETWEEN '2010-01-01' AND '2010-01-02);
但是,假設一個StartTime
開始有一天,各地11:00 PM說了,EndTime
是一段時間的第二天,也許凌晨3:00。在這些情況下,我只想分配當天發生的那一段時間。所以,1小時將走向第一天,3小時將走向下一個。
SUM(
TIME_TO_SEC(
TIMEDIFF(
IF(`EndTime`>DATE_ADD('2010-01-01', INTERVAL 1 DAY), DATE_ADD('2010-01-01', INTERVAL 1 DAY), `EndTime`),
IF(`StartTime`<'2010-01-01', '2010-01-01', `StartTime`)
)
)/60/60
)
這樣做的想法是,如果EndTime
比一天結束的時候多,那麼我們就用這一天的結束,而不是。如果StartTime
小於一天的開始時間,那麼我們將僅使用一天的開始。
所以,我然後需要將所有達包裝成的東西,將產生一個表,看起來像這樣的:
date, total
2010-01-01, 0
2010-01-02, 1.53
2010-01-03, 5.33
我想這個查詢會工作:
SELECT
`date`,
SUM(
TIME_TO_SEC(
TIMEDIFF(
IF(`EndTime`>DATE_ADD(`date`, INTERVAL 1 DAY), DATE_ADD(`date`, INTERVAL 1 DAY), `EndTime`),
IF(`StartTime`<`date`, `date`, `StartTime`)
)
)/60/60
) AS `total_hours`
FROM
(SELECT * FROM `logs` WHERE `StartTime` BETWEEN '2010-08-01' AND '2010-08-31') AS logs_small,
(SELECT DATE_ADD("2010-08-01", INTERVAL `number` DAY) AS `date` FROM `numbers` WHERE `number` BETWEEN 0 AND 30) AS `dates`
GROUP BY `date`;
注意numbers
引用的表是隻有一列的表,number
,帶有一系列整數,0,1,2,3等。我在這裏使用它來生成一系列日期,這很好地工作。
這個查詢的問題是我得到不準確的數據。具體來說,logs
表中有一個EndDate進入第二天的行在第二天不會計入任何時間。例如,如果我有一排開始於2010-08-01 23:00:00並於2010-08-02 01:00:00結束,則2010-08-02產生的行將加起來爲0。
有沒有更好的方法來做到這一點?理想情況下,我希望在沒有任何記錄與其匹配的日期獲得0
而不是null
。
編輯:爲了澄清,我希望把這個:
id, StartTime, EndTime
0, 2000-01-01 01:00:00, 2000-01-01 04:00:00
1, 2000-01-01 23:00:00, 2000-01-02 05:00:00
2, 2000-01-02 00:00:00, 2000-01-04 01:00:00
...這個:
date, total_hours
2000-01-01, 4
2000-01-02, 29
2000-01-03, 24
2000-01-04, 1
2000-01-05, 0
解決方案
感謝jim31415提出解決方案!我翻譯了他的回答了在MySQL中可使用的功能以及與此想出了:
SELECT `d`.`Date`,
SUM(COALESCE(
(CASE WHEN t.StartTime >= d.Date AND t.EndTime < DATE_ADD(d.Date, INTERVAL 1 DAY) THEN TIME_TO_SEC(TIMEDIFF(t.EndTime, t.StartTime))
WHEN t.StartTime < d.Date AND t.EndTime <= DATE_ADD(d.Date, INTERVAL 1 DAY) THEN TIME_TO_SEC(TIMEDIFF(t.EndTime,d.Date))
WHEN t.StartTime >= d.Date AND t.EndTime > DATE_ADD(d.Date, INTERVAL 1 DAY) THEN TIME_TO_SEC(TIMEDIFF(DATE_ADD(d.Date, INTERVAL 1 DAY),t.StartTime))
WHEN t.StartTime < d.Date AND t.EndTime > DATE_ADD(d.Date, INTERVAL 1 DAY) THEN 24*60*60
END), 0)
)/60/60 ConnectionTime
FROM (SELECT DATE_ADD('2011-03-01', INTERVAL `number` DAY) AS `Date` FROM `numbers` WHERE `number` BETWEEN 0 AND 30) AS d
LEFT JOIN `logs` t ON (t.StartTime >= d.Date AND t.StartTime < DATE_ADD(d.Date, INTERVAL 1 DAY))
OR (t.EndTime >= d.Date AND t.EndTime < DATE_ADD(d.Date, INTERVAL 1 DAY))
OR (t.StartTime < d.Date AND t.EndTime > DATE_ADD(d.Date, INTERVAL 1 DAY))
GROUP BY d.Date
ORDER BY d.Date;
我也應該注意,EndTime
空值並不適用於我的情況,因爲我是從舊的日誌文件閱讀在我的應用程序。如果你需要他們,吉姆的帖子讓他們有相當好的概述。
工作很好!謝謝!我將發佈我用於MySQL版本的內容作爲對我的文章的修改。 – Brad 2011-03-14 23:56:56