2012-05-17 58 views
3

我在一個按時間存儲日誌數據的數據庫中有一個表。有一天,數據庫中可能會有一百萬行。時間不是固定的時間間隔。它有幾個指標,包括時間。我想要做的是構建一個查詢,每個時間間隔將返回一行一行。例如,我可以做一個查詢,每15分鐘返回一行一天。這將返回24 * 60 = 96行。返回的每一行實際上都是請求間隔之前數據庫中最近的一行(因爲數據庫中的數據不會等於請求的間隔)。使用MySQL的時間間隔SQL查詢

我不知道該怎麼做。我不能只查詢一組特定索引和時間間隔的所有行,因爲它會將超過一千兆字節的數據加載到內存中,這太慢了。有沒有任何有效的方法來使用SQL來做到這一點。我正在使用MySQL數據庫。我會開到改變表索引的/ etc ...

TIME 

11:58 
12:03 
12:07 
12:09 
12:22 
12:27 
12:33 
12:38 
12:43 
12:49 
12:55 

如果我想從12:00查詢此爲15分鐘間隔至下午1:00,我會回來:

11:58 (nearest 12:00) 
12:09 (nearest 12:15) 
12:27 (nearest 12:30) 
12:43 (nearest 12:45) 
12:55 (nearest 1:00) 

如果使它更容易,我還可以將時間存儲爲一個數字(即1970年以來的ms)。在上面的查詢中,這將是900000毫秒的時間間隔。

+0

如果對於一個給定的時間間隔超過一排,應該使用哪個行?或者它應該是行的某種組合? – wallyk

+1

相關:[SELECT/GROUP BY - 時間段(10秒,30秒等)](http://stackoverflow.com/questions/3086386/select-group-by-segments-of-time-10-seconds -30秒等) –

+0

你是否需要每個間隔出現?如果沒有記錄怎麼辦?如果一條記錄最接近兩個不同的時間間隔(即11:58,12:27,1:14將會有12:14最接近12:15,12:30和12:45) –

回答

4

所以,我以爲是這樣的:

SELECT 
    MIN(timeValue) 
FROM e 
GROUP BY (to_seconds(timeValue) - (to_seconds(timeValue) % (60 * 5))) 

..would爲你做它,但這隻在整個表返回MIN(TIMEVALUE)。如果四捨五入到最接近的5分鐘的秒數在它自己的列中,它就可以工作。

見每Andiry SQL Fiddle

編輯,這工作:(http://sqlfiddle.com/#!2/bb870/6

SELECT MIN(t) 
FROM e 
GROUP BY to_seconds(t) DIV (60 * 5) 

但是,這只是給一個行:(http://sqlfiddle.com/#!2/bb870/7

SELECT MIN(t) 
FROM e 
GROUP BY to_seconds(t) - (to_seconds(t) % (60 * 5)) 

任何人都知道爲什麼嗎?

+0

'to_seconds(timeValue)DIV(60 * 5)'將會是等價的並且更加簡潔你爲什麼說這隻會返回整個表的最小值?在這裏對行進行分組,因此這會返回每個組的MIN()。(儘管我認爲MAX()而不是MIN()會更接近OP的結果。) –

+0

感謝DIV tip,年齡prolly右MAX() - 我只是想要接近目標。 – Andrew

+0

@Andrew我希望它是一個SQL小提琴的bug,而不是實際的mysql行爲。 – Aprillion

0

我想不出在一個查詢中完成所有操作的好方法。也許別人能想到更好的辦法,但也許你可以使用這樣的事情:

$startTime = mktime(12, 0); 
$endTime = mktime(13, 0); 
$queries = array(); 
for ($i = $startTime; $i <= $endTime; $i += 900) 
    $queries[] = "SELECT MAX(timeValue) FROM table1 WHERE timeValue < '". date("G:i", $i) ."'"; 

$query = implode("\nUNION\n", $queries); 

我才意識到,這裏假設你正在使用PHP。如果你不是,那麼就使用生成的查詢,這將是這樣的:

SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:00' 
UNION 
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:15' 
UNION 
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:30' 
UNION 
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:45' 
UNION 
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '13:00' 

不知道,如果<比較將正常工作100%,這些字符串值,但我絕對認爲這將是一個好主意將它們切換到unix時間戳(或1970年以來的ms,如果您需要這麼多粒度)。我發現使用日期/時間的整數值而不是字符串總是更容易。

+0

謝謝,我會試一試,我認爲這個問題是我需要在1分鐘到15分鐘的時間內完成這一整天,並且這相當於96到1440個查詢可能會很慢 – user1387312

0

我認爲使用函數很容易,我沒有注意到很大的性能影響,儘管遊標可能會更好地預製,這取決於時間之間有多少行。

CREATE TABLE TEST_TIMES (EventTime datetime) 
-- skipping INSERTS of your times 

CREATE FUNCTION fn_MyTimes (@StartTime datetime, @EndTime datetime, @Minutes int) 
    RETURNS @TimeTable TABLE (TimeValue datetime) 
AS BEGIN 
    DECLARE @CurrentTime datetime 
    SET @CurrentTime = @StartTime 
    WHILE @CurrentTime <= @EndTime 
    BEGIN 
     INSERT INTO @TimeTable VALUES (@CurrentTime) 
     SET @CurrentTime = DATEADD(minute, @Minutes, @CurrentTime) 
    END 
    RETURN 
END 

CREATE FUNCTION fn_ClosestTime (@CheckTime datetime) 
    RETURNS datetime 
AS BEGIN 
    DECLARE @LowerTime datetime, @HigherTime datetime 

    SELECT @LowerTime = MAX(EventTime) 
    FROM TEST_TIMES 
    WHERE EventTime <= @CheckTime 

    SELECT @HigherTime = MAX(EventTime) 
    FROM TEST_TIMES 
    WHERE EventTime >= @CheckTime 

    IF @LowerTime IS NULL RETURN @HigherTime -- both null? then null 
    IF @HigherTime IS NULL RETURN @LowerTime 

    IF DATEDIFF(ms, @LowerTime, @CheckTime) < DATEDIFF(ms, @CheckTime, @HigherTime) 
     RETURN @LowerTime 
    RETURN @HigherTime 
END 

SELECT TimeValue, dbo.fn_ClosestTime(TimeValue) as ClosestTime 
FROM fn_MyTimes('2012-05-17 12:00', '2012-05-17 13:00', 15) 

結果:

TimeValue    ClosestTime 
----------------------- ----------------------- 
2012-05-17 12:00:00.000 2012-05-17 11:58:00.000 
2012-05-17 12:15:00.000 2012-05-17 12:09:00.000 
2012-05-17 12:30:00.000 2012-05-17 12:27:00.000 
2012-05-17 12:45:00.000 2012-05-17 12:43:00.000 
2012-05-17 13:00:00.000 2012-05-17 12:55:00.000 
+0

我看到MYSQL不允許函數返回表,我的搜索想出的第一個鏈接顯示了它,但它[是一個插件](http://antbits.blogspot.com/2009/01/table-functions -in-mysql.html)。 –