n-ая запись на основе даты в запросе MySQL - PullRequest
2 голосов
/ 28 июня 2011

Я создаю веб-график на основе jquery, который отображает данные о погоде.Данные загружаются через Ajax -> PHP -> MySQL.База данных MySQL содержит записи о различных параметрах для каждой минуты за последние 10 лет ... (таким образом, огромное количество записей).Я хочу, чтобы пользователи могли создавать график для настраиваемого диапазона дат, но ограничить количество данных, которые я извлекаю для диапазонов дат, дольше, чем несколько дней.Т.е., если они запрашивают данные за недели, мой php-код должен возвращать только 1 значение данных в час.Я не хочу выполнять какое-либо усреднение или обработку на стороне сервера такого рода - я хочу извлечь только каждую n-ую запись из mysql - чтобы получить управляемый объем данных.

Моя проблема в том, что в моей базе данных нет поля номера записи, и я НЕ МОГУ ИЗМЕНИТЬ формат базы данных.Есть ли способ, которым я мог бы сделать это на основе фактических значений даты?Как, например, приведение к метке времени Unix, тогда выберите запись, только если дата делится на некоторое число?(Я бы рассчитал число на основе длины временного диапазона, чтобы получить фиксированное количество точек)

Есть какие-нибудь мысли о хороших способах сделать это?Если бы было решение, которое позволило бы мне напрямую выбирать даже временные интервалы, это было бы идеально.(т.е. каждые 5 минут, 10 минут, 1 час, 5 часов и т. д.)

РЕДАКТИРОВАТЬ: поле имеет формат MySQL dateTime !!Спасибо, что попросили разъяснений!

Ответы [ 3 ]

1 голос
/ 29 июня 2011

Вы можете использовать функции MOD () и UNIX_TIMESTAMP () в предложении SQL WHERE

SELECT * FROM WEATHER WHERE MOD(UNIX_TIMESTAMP(Time), Divisor) = 0

Получит вам только записи с Временами, которые делятся на Дивизор. Делителем будет любой приращение времени, для которого вы хотите получить данные (300 за каждые 5 минут, 5400 за каждые 1,5 часа и т. Д.).

Поскольку в UNIX Time используется 32-битное int, ваш стандартный тип данных INT в MySQL будет работать нормально.

0 голосов
/ 29 июня 2011

Как, скажем, приводить к метке времени Unix, затем выбирать запись только в том случае, если дата делится на некоторое число?

Проблема с этим, и большинство подходов заключается в том, что вам все равно нужно прочитать все последовательные точки (если у вас нет индексированных столбцов, содержащих различные представления временной метки), поэтому вы можете уменьшить размер набора результатов, но не уменьшать объем работ, необходимых для его извлечения.

Можете ли вы создать новую таблицу (необязательно находиться в той же базе данных / сервере - вы все еще можете подключаться к необработанным данным с помощью механизма объединения)? Таким образом, вы могли бы создать таблицу временных меток с разной степенью детализации в башнях Ханоя, например,

date time       level
-------------   -----
201101010000    0
201101010010    6
201101010020    6
201101010030    5
201101010040    6
201101010050    6
201101010100    4
201101010110    6
201101010120    6
201101010130    5
...
201101020000    3
...

Таким образом, вы можете ВЫБРАТЬ из этой сказки на соответствующем уровне детализации и присоединиться к базовым необработанным данным.

Вышеуказанный аргумент может быть использован как функция для агрегирования данных - но без возможности поиска из вам все равно нужно прочитать все промежуточные строки в данных src.

Если бы существовало решение, которое позволило бы мне напрямую выбирать четные интервалы времени

Что-то вроде ....

 SELECT DATE_FORMAT(yourdate, SUBSTR('%Y%m%d%H%i%s',0,2*@level)) as t,
 AVG(value)
 FROM yourtable
 WHERE yourdate BETWEEN @datestart AND @dateend
 GROUP BY DATE_FORMAT(yourdate, SUBSTR('%Y%m%d%H%i%s',0,2*@level))
 ORDER BY 1;

(как указано выше - без присоединения второй таблицы или другого способа выбора только повторной выборки данных с использованием индекса, при использовании агрегата fn нет снижения производительности).

0 голосов
/ 29 июня 2011

Вы можете преобразовать DATETIME в метку времени UNIX, разделить его на количество секунд в требуемом интервале (10 минут в следующем примере), а затем использовать GROUP BY, чтобы уменьшить до одной строки на отдельное значение.

SELECT FLOOR(UNIX_TIMESTAMP(datetime_col)/600) AS ts, * FROM WEATHER 
WHERE datetime_col BETWEEN ? AND ?
GROUP BY ts

Это не будет очень быстро, потому что нужно вычислить ts для каждой строки, а затем сгруппировать по ней как неиндексированный столбец.

Также это зависит от нестандартного поведения MySQL, которое допускает неоднозначные запросы GROUP BY. То есть он возвращает произвольную строку из группы, определенную механизмом хранения. На практике это первая строка, сохраненная физически, но это может привести к путанице в зависимости от механизма хранения, индексов покрытия и т. Д.

Альтернатива: вы можете использовать переменную пользователя для подсчета строк и возвращать только первую строку при изменении интервала.

SET @interval := 0;
SET @row := 0;
SELECT t.* FROM (
SELECT (@i:=FLOOR(UNIX_TIMESTAMP(datetime_col)/600)),
  IF(@interval<>@i),@row:=0,@row:=@row+1) AS row, @interval:=@i, *
FROM WEATHER
WHERE datetime_col BETWEEN ? AND ?
) AS t
WHERE t.row = 0;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...