2014-12-30 3 views
0

В моей таблице у меня есть поля (с именем id, двоичные и временные метки), получающие данные от датчика, установленного над дверью, когда дверь открывается, она отправляет двоичное значение как 1 с меткой времени и ее собственным идентификатором. когда он закрыт, он отправляет двоичное значение как 0, а также метку времени и идентификатор. и да, он отправляет непрерывные данные, а не когда при открытии просто отправляет данные и останавливается, скорее, он продолжает отправлять данные с одинаковым значением для двоичного и id, за исключением отметки времени. например, вчера, когда дверь была открыта в течение 2-х секунд он послал данные, как это:вычисление общего времени с использованием timestamp

------------------------ 
id---binary---timestamp 
------------------------ 
XX-----1------2014-12-29 21:09:08 
XX-----1------2014-12-29 21:09:08 
XX-----1------2014-12-29 21:09:08 
XX-----1------2014-12-29 21:09:08 
XX-----1------2014-12-29 21:09:08 
XX-----1------2014-12-29 21:09:09 
XX-----1------2014-12-29 21:09:09 
XX-----1------2014-12-29 21:09:09 
XX-----1------2014-12-29 21:09:09 
XX-----1------2014-12-29 21:09:09 
XX-----0------2014-12-29 21:09:10 
XX-----0------2014-12-29 21:09:10 
XX-----0------2014-12-29 21:09:10 
........................................so on.. 

выше изображения можно найти на целый день, как много раз дверь открылась с 1 значением и остальными 0 значения времени.

Теперь, я хочу рассчитать общую продолжительность времени, чтобы показать на графике каждый день, как долго дверь была открыта. Но проблема в том, что я не знаю из выше данных, как рассчитать продолжительность времени, используя временную метку. Я знаю, что могу рассчитывать с помощью функций TIMEDIFF() и TIME_TO_SEC(), но это только тогда, когда у меня есть время начала и окончания - в моем случае у меня нет.

Я также подумал о том, чтобы выбрать все значение где binary = 1 и суммировать их вместе, но это не время реального времени, потому что мой датчик когда-то отправляет одинаковые данные 5 раз/сек, когда-то отправляет 3 раза/сек. Если было исправлено, что всегда отправляя 5data/sec, тогда я могу суммировать итог и разделить на 5, чтобы найти одну секунду, но это не так.

У кого-нибудь есть идея решить это?

Заранее спасибо .. :)

ответ

1

Хорошо, есть несколько возможных ответов.

Если вы уверены, что у вас есть запись для каждого второго в вашей таблице, вы можете просто сделать это:

select 
id, `binary`, 
sec_to_time(count(distinct `timestamp`)) 
from 
t 
where `timestamp` between concat(curdate(), ' 00:00:00') and concat(curdate(), ' 23:59:59') 
/*you could also do 
    where date(timestamp) = curdate() 
but having a function on a column does not allow MySQL to use an index*/ 
group by id, `binary` 

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

С distinct вы получите только уникальные записи в этом столбце. С count вы считаете секунды, и с sec_to_time вы превращаете его в более удобный для чтения формат.

Вы можете сутенером, указав индекс unique по столбцам (id, binary, timestamp) и вместо insert ... сделать insert ignore .... Таким образом, вы получите только одну запись в секунду в таблице.

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

SELECT `binary`, SEC_TO_TIME(SUM(secondsOnOffPerGroup)) 
FROM (
    SELECT 
    id, `binary`, valueChangeGroup, TIMESTAMPDIFF(SECOND, MIN(`timestamp`), MAX(`timestamp`)) + 1 as secondsOnOffPerGroup 
    FROM (
     SELECT 
     t.*, 
     @valueChangeGroup := IF(@prevB != `binary`, @valueChangeGroup + 1, @valueChangeGroup) as valueChangeGroup, 
     @prevB := `binary` 
     FROM 
     t 
     , (SELECT @prevB := null, @valueChangeGroup := 0) var_init_subquery_alias 
     WHERE 
     `timestamp` between concat(curdate(), ' 00:00:00') and concat(curdate(), ' 23:59:59') 
     ORDER BY id, `timestamp` 
    ) sq 
    GROUP BY id, `binary`, valueChangeGroup 
) sq2 
GROUP BY `binary` 

Что мы здесь делаем, это заказать по id и отметке времени в первую очередь. Затем мы увеличиваем переменную, если значение текущей строки отличается от предыдущей строки. Во внешнем запросе мы группируем эту переменную и получаем минимальную метку времени для каждой группы, поэтому мы можем рассчитать разницу. Я добавляю + 1, потому что, когда дверь открыта или закрыта всего на одну секунду, разница, очевидно, равна 0. Если она открыта или закрыта 2 секунды, разница составляет 1.В самом внешнем запросе мы группируем по binary и суммируем секунды.

  • увидеть его работы вживую в sqlfiddle
+0

на самом деле у меня есть несколько записи на каждые секунды. сейчас его 40 записей в секунду. поэтому есть несколько данных с одинаковым двоичным значением и временной меткой, означает, что существует так много повторений. в таком случае, не думайте, что результат не будет точным? но да, ваш код кажется очень близким, возможно, это то, что я искал. позвольте мне проверить его более глубоко ... спасибо за ответ. – hypocrite420

+0

Не имеет значения, сколько записей у вас есть на каждую секунду (за исключением производительности). В первом решении важно только, чтобы была запись для каждой второй части дня. Во втором решении это не имеет значения, и не имеет значения, есть ли несколько записей в секунду. С подсказкой об уникальном индексе и игнорировании вставки я просто хотел обратиться к проблеме с производительностью. – fancyPants

1

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

У вас есть граничные условия, как, например:

Start timestamp - 2014-12-29 00:00:01 
End timestamp - 2014-12-29 00:00:00 

Теперь подойдите так:

1) Set count=0 and totalOpenTime=0 
2) if the row fetched have binary '1' set count = count + 1 then fetch next row 
3) if in next row binary is '0' then add count to totalOpenTime and set count to 0 
    but if in next row binary is '1' then set count = count + 1 and fetch next row 
4) do this until timestamp < End timestamp 

Надеется, что это помогает :)

+0

ну, я не уверен, как написать точный код для вашей точки (3). но проблема я не понимаю, как я установлю границу. здесь я просто предоставил данные в течение нескольких секунд, поэтому кажется, что легко определить начальную и конечную временную метку. но есть миллионы данных, я могу установить границу на один день, как 2014-12-29 00:00:00 до 2014-12-29 23:59:59. и датчик, отправляющий 40data/second сейчас. так что в день, как и 40x60x60x24 данных. Тогда как я могу сделать эту проверку по строкам? извините, но если вы не возражаете, можете объяснить бит больше? Спасибо за ответ. – hypocrite420