Как найти разницу во времени для изменения состояния MySQL - PullRequest
0 голосов
/ 02 января 2019

Мои данные как ниже.

id  device      state   timestamp
250708  1004-3-007294   9   02/01/2019 9:20
250694  1004-3-007294   8   02/01/2019 9:31
250769  1004-3-007294   7   02/01/2019 10:04
250774  1004-3-007294   5   02/01/2019 10:13
250778  1004-3-007294   4   02/01/2019 10:20
250785  1004-3-007294   11  02/01/2019 10:27
250808  1004-3-007294   4   02/01/2019 10:29
250814  1004-3-007294   11  02/01/2019 10:36
250795  3091-5-007208   7   02/01/2019 10:39
250819  3091-5-007208   5   02/01/2019 10:42
250832  3091-5-007208   4   02/01/2019 10:58
250837  3091-5-007208   11  02/01/2019 11:02
250846  3091-5-007208   4   02/01/2019 11:13

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

Ответы [ 4 ]

0 голосов
/ 02 января 2019

Вы можете использовать JOIN для этого. Далее предполагается, что существует ровно один переход 5-> 4, поэтому не стоит проверять, был ли это первый переход:

SELECT t1.id, t2.id, TIMESTAMPDIFF(SECOND, t1.timestamp,t2.timestamp) AS diff
FROM       t AS t1
INNER JOIN t AS t2 ON t2.device = t1.device AND t2.state = 4 AND t2.timestamp > t1.timestamp
LEFT  JOIN t AS tx ON t1.device = tx.device AND tx.timestamp > t1.timestamp AND tx.timestamp < t2.timestamp
WHERE t1.state = 5 AND tx.id IS NULL

Соединение влево в вышеприведенном примере гарантирует, что сопоставляется только последовательный переход (например, 250774 соединяется с 250778 и 250808, но последний отбрасывается).

Демонстрация на дб <> скрипка

0 голосов
/ 02 января 2019

Я думаю, что вы можете использовать условное агрегирование:

select device,
       timestampdiff(second,
                     min(case when status = 4 then timestamp end),
                     max(case when status = 5 then timestamp end)
                    ) as diff_in_seconds
from t
group by device;
0 голосов
/ 02 января 2019

Если вы используете более позднюю версию MySQL, вы можете использовать функцию LEAD, чтобы получить следующее состояние для каждой строки

SELECT  *,
        LEAD(State) OVER(PARTITION BY device ORDER BY TimeStamp) AS NextState,
        LEAD(TimeStamp) OVER(PARTITION BY device ORDER BY TimeStamp) AS NextTimeStamp
FROM    t;

Который за одно устройство даст:

id      device          state   timestamp               NextState       NextTimeStamp
---------------------------------------------------------------------------------------------
250795  3091-5-007208   7       2019-02-01 10:39:00         5           2019-02-01 10:42:00
250819  3091-5-007208   5       2019-02-01 10:42:00         4           2019-02-01 10:58:00   <---
250832  3091-5-007208   4       2019-02-01 10:58:00         11          2019-02-01 11:02:00
250837  3091-5-007208   11      2019-02-01 11:02:00         4           2019-02-01 11:13:00
250846  3091-5-007208   4       2019-02-01 11:13:00        NULL                 NULL

Это позволит вам определить, когда состояние изменилось с 5 на 4. Вам просто нужно поместить вышеуказанный запрос в подзапрос и применить условие where:

SELECT  t.device,
        t.TimeStamp AS ChangedToFive,
        t.NextTimeStamp AS ChangedFromFiveToFour
FROM    (   SELECT  *,
                    LEAD(State) OVER(PARTITION BY device ORDER BY TimeStamp) AS NextState,
                    LEAD(TimeStamp) OVER(PARTITION BY device ORDER BY TimeStamp) AS NextTimeStamp
            FROM    t
        ) AS t
WHERE   t.State = 5
AND     t.NextState = 4;

Если вы используете более старую версию, которая не поддерживает использование LEAD, то вам потребуется использовать связанные подзапросы для репликации функциональности:

SELECT  t.device,
        t.TimeStamp AS ChangedToFive,
        t.NextTimeStamp AS ChangedFromFiveToFour
FROM    (   SELECT  *,
                    (   SELECT  TimeStamp
                        FROM    t AS t2
                        WHERE   t2.Device = t.Device
                        AND     t2.TimeStamp > t.TimeStamp
                        ORDER BY TimeStamp
                        LIMIT 1
                    ) AS NextTimeStamp
            FROM    t
            WHERE   t.State = 5
            AND     (   SELECT  State
                        FROM    t AS t2
                        WHERE   t2.Device = t.Device
                        AND     t2.TimeStamp > t.TimeStamp
                        ORDER BY TimeStamp
                        LIMIT 1
                    ) = 4 -- next state = 4 to satisfy changing from 5 to 4
        ) AS t;

Примеры на БД <> Fiddle

0 голосов
/ 02 января 2019
SELECT A.Device, TIMESTAMPDIFF(SECOND,B.t2,A.t1) as differenceintime
FROM
( SELECT device, MIN(timestamp) as t1
  FROM tableName
  WHERE state = 5
  GROUP BY device
) as A
INNER JOIN
( SELECT device, MIN(timestamp) as t2
  FROM tableName
  WHERE state = 4
  GROUP BY device
) as B

ON A.Device = B.Device
...