Как получить выбранные строки, которые имеют первые вхождения до изменения значения столбца в MYSQL8 - PullRequest
3 голосов
/ 10 марта 2020

У меня есть таблица MYSQL8 с Event_TimeStamp и FinalStateand, она выглядит следующим образом

+---------------------------+---------------+
|"Event_TimeStamp"          |"FinalState"   |
+---------------------------+---------------+
|"2020-03-09 04:57:45.729"  |"Available"    |
|"2020-03-09 05:14:59.659"  |"Available"    |
|"2020-03-09 05:27:56.341"  |"Available"    |
|"2020-03-09 05:41:01.554"  |"Available"    |
|"2020-03-09 05:58:07.803"  |"Available"    |
|"2020-03-09 06:06:09.745"  |"Available"    |
|"2020-03-09 06:18:07.663"  |"Available"    |
|"2020-03-09 06:26:24.273"  |"Available"    |
|"2020-03-09 09:29:53.165"  |"Offline"      |
|"2020-03-09 10:28:00.514"  |"Available"    |
|"2020-03-09 12:47:54.130"  |"Available"    |
|"2020-03-09 13:01:30.117"  |"Available"    |
|"2020-03-09 13:01:59.774"  |"Offline"      |
|"2020-03-09 13:19:15.772"  |"Available"    |
|"2020-03-09 14:19:51.521"  |"Available"    |
|"2020-03-09 14:50:16.872"  |"Offline"      |
+---------------------------+---------------+

Мне нужно извлечь строки из вышеперечисленных так, чтобы в них были строки с первым «Доступно» и «В автономном режиме», поэтому выходные данные будут выглядеть так:

+---------------------------+---------------+
|"Event_TimeStamp"          |"FinalState"   |
+---------------------------+---------------+
|"2020-03-09 04:57:45.729"  |"Available"    |
|"2020-03-09 09:29:53.165"  |"Offline"      |
|"2020-03-09 10:28:00.514"  |"Available"    |
|"2020-03-09 13:01:59.774"  |"Offline"      |
|"2020-03-09 13:19:15.772"  |"Available"    |
|"2020-03-09 14:50:16.872"  |"Offline"      |
+---------------------------+---------------+

Я пробовал несколько способов с GROUP BY, но я получаю только первые записи для каждого из FinalState, а не остальные.

Есть ли способ сделать это с помощью QUERY или я должен написать это в PHP?

Ответы [ 4 ]

1 голос
/ 11 марта 2020

Вы можете использовать lag() и lead() для показа записей, чья final_state отличается от предыдущей или следующей строки:

select
    event_timestamp,
    final_state
from (
    select 
        t.*, 
        lag(final_state) over(order by event_timestamp)  lag_final_state,
        lead(final_state) over(order by event_timestamp) lead_final_state
    from mytable t
) t
where final_state <> lag_final_state or final_state <> lead_final_state
0 голосов
/ 12 марта 2020

Этот запрос решил мою проблему. Все благодаря @ GMB

SELECT
    Event_TimeStamp,
    FinalState
FROM (
    SELECT
        t.*,
        COALESCE(LAG(FinalState) over(ORDER BY Event_TimeStamp), 'offline')  lag_final_state,
        COALESCE(lead(FinalState) over(ORDER BY Event_TimeStamp), 'offline') lead_final_state
    FROM (
        SELECT
            Event_TimeStamp, 
            FinalState
        FROM AgentTraceData
        WHERE Event_TimeStamp BETWEEN '2019-11-17' AND '2020-03-10 23:59:59.999' AND username = 'xxxx' ORDER BY Event_TimeStamp
        ) t
    ) t
WHERE FinalState <> lag_final_state

, который дает следующий результат

+---------------------------+-------------+
|"Event_TimeStamp"          | "FinalState"|
+---------------------------+-------------| 
|"2019-11-18 02:01:16.395"  |"online"     |
|"2019-11-18 04:34:59.739"  |"offline"    |
|"2019-11-18 04:45:08.354"  |"online"     |
|"2019-11-18 07:30:13.909"  |"offline"    |
|"2019-11-18 08:00:20.647"  |"online"     |
|"2019-11-18 10:30:08.698"  |"offline"    |
+---------------------------+-------------+

Я постараюсь объяснить как можно больше.

Сначала нам нужно выполнить запрос с SELECT *, чтобы увидеть все появившиеся столбцы.

Вывод будет выглядеть следующим образом

+---------------------------+---------------+-------------------+------------------+
|"Event_TimeStamp"          |"FinalState"   |"lag_final_state"  |"lead_final_state"|
+---------------------------+---------------+-------------------+------------------+
|"2019-11-18 02:01:16.395"  |"online"       |"offline"          |"online"          |
|"2019-11-18 04:34:59.739"  |"offline"      |"online"           |"online"          |
|"2019-11-18 04:45:08.354"  |"online"       |"offline"          |"online"          |
+---------------------------+---------------+-------------------+------------------+

В соответствии с моим требованием я хотел знать следующее значение FinalState, поэтому final_state <> lead_final_state не потребовалось.

Я добавил COALESCE(), потому что LEAD() и LAG() дадут NULL значения для строк, которые не существуют выше или после первого запроса SELECT.

0 голосов
/ 11 марта 2020

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

with cte as
(select CAST('2020-03-09 04:57:45.729' as datetime) as Event_timestamp,'Available' as Finalstate union
select '2020-03-09 05:14:59.659','Available' union
select '2020-03-09 09:29:53.165','Offline' union
select '2020-03-09 10:28:00.514','Available')

select x.Event_timestamp,x.Finalstate
from
(select *,lag(Finalstate) Over(Order by Event_timestamp) as lag_status
from cte ) x
where x.Finalstate<>coalesce(lag_status,'Z')

Вот db-скрипка: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=cb59ec79e7be1363961971cea4308dff

Надеюсь, это поможет .

0 голосов
/ 11 марта 2020

Это возможно, используя соединения. Я использовал events в качестве примера имени базы данных.

SELECT x.* 
  FROM events x
  JOIN
     (
       SELECT MIN(c.id) id 
         FROM events a
         LEFT 
         JOIN events b 
           ON b.FinalState = a.FinalState 
          AND b.id = a.id - 1 
         LEFT 
         JOIN events c 
           ON c.FinalState = a.FinalState
          AND c.id >= a.id
         LEFT
         JOIN events d
           ON d.FinalState = a.FinalState
          AND d.id = c.id + 1
        WHERE b.id IS NULL 
          AND c.id IS NOT NULL
          AND d.id IS NULL
        GROUP 
           BY a.id
     ) y
    ON y.id = x.id; 
...