2012-05-17 2 views
3

У меня есть таблица в базе данных, которая хранит данные журнала по времени. На один день в db может быть миллион строк. Времена не имеют никакого регулярного интервала. Он имеет несколько индексов, включая время. Я хочу создать запрос, который будет возвращать набор строк с одной строкой за промежуток времени. Например, я мог бы сделать запрос, чтобы возвращать 1 строку каждые 15 минут в течение дня. Это вернет 24 * 60 = 96 строк. Каждая возвращенная строка фактически будет ближайшей строкой в ​​db до запрошенного интервала (поскольку данные в базе данных не будут равны запрошенному интервалу).Временной интервал SQL-запрос с MySQL

Я в затруднении, как это сделать. Я не могу просто запросить все строки для определенного набора индексов и временного интервала, так как он загрузил бы больше гигабайта данных в память, что слишком медленно. Есть ли эффективный способ сделать это с помощью SQL. Я использую базу данных MySQL. Я был бы открыт для изменения индексов таблицы/и т.д. ...

TIME 

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

Если бы я хотел, чтобы запросить это в течение 15-минутного интервала от 12:00 до 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 года). В вышеприведенном запросе это будет интервал в 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, 01: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 минут, находятся в собственном столбце.

См SQL Fiddle

Редактировать за Andiry, это работает: (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, yr oly right about MAX() - Я просто пытаюсь приблизиться к цели. – Andrew

+0

@ Аndrew я надеюсь, что это SQL Ошибка скрипта, а не фактическое поведение 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 (или ms с 1970 года, если вам нужна такая гранулярность). Я нашел, что всегда проще работать с целыми значениями для даты/времени вместо строк.

+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 -в-mysql.html). –

Смежные вопросы