Справка по SQL-запросам: как выбрать только начальные и конечные строки групп (Oracle)? - PullRequest
2 голосов
/ 17 марта 2010

(извиняюсь за название этого вопроса - я не был слишком уверен, как это объяснить)

Не уверен, что это можно сделать в SQL. Ниже приведен (несколько урезанный) пример таблицы журнала событий.

EVENT      ID          DATE      TIME
---------  ----------  --------  ----
ONE_THING  0006241800  20091109  1719
ONE_THING  0006944800  20091109  1720
ANOTHER    0007517110  20091109  1721
ANOTHER    0007214240  20091109  1721
ANOTHER    0006907900  20091109  1725
ANOTHER    0006501580  20091109  1727
ONE_THING  0006944800  20091109  1737
ANOTHER    0005749820  20091109  1737
ANOTHER    0006810500  20091109  1738
ANOTHER    0007481970  20091109  1738
ANOTHER    0006331740  20091109  1739
ANOTHER    0007253840  20091109  1739
ANOTHER    0006929280  20091109  1747
ANOTHER    0007297950  20091109  1749
ANOTHER    0005055560  20091109  1751
ANOTHER    0006092320  20091109  1751
ONE_THING  0001668720  20091109  1753
ONE_THING  0007218000  20091109  1754

Я ищу, чтобы найти группы случаев ДРУГОГО, где не было никакого другого события в группе и для периодов времени, превышающих 2 минуты.

Итак, в приведенном выше наборе данных первая группа будет:

ANOTHER    0007517110  20091109  1721
ANOTHER    0007214240  20091109  1721
ANOTHER    0006907900  20091109  1725
ANOTHER    0006501580  20091109  1727

и второй будет:

ANOTHER    0005749820  20091109  1737
ANOTHER    0006810500  20091109  1738
ANOTHER    0007481970  20091109  1738
ANOTHER    0006331740  20091109  1739
ANOTHER    0007253840  20091109  1739
ANOTHER    0006929280  20091109  1747
ANOTHER    0007297950  20091109  1749
ANOTHER    0005055560  20091109  1751
ANOTHER    0006092320  20091109  1751

И в идеале я бы хотел получить:

ANOTHER    0007517110  20091109  1721
ANOTHER    0006501580  20091109  1727

и:

ANOTHER    0005749820  20091109  1737
ANOTHER    0006092320  20091109  1751

Или еще лучше:

EVENT      DATE      TIME_START  TIME_END
---------  --------  ----------  --------
ANOTHER    20091109  1721        1727
ANOTHER    20091109  1737        1751

Я думал о сравнении строк, но может быть, есть лучший способ? Буду признателен за любые советы по этому. Решение просто должно работать - оно не обязательно должно быть элегантным или элегантным.

PS> Я использую Oracle.

Ответы [ 5 ]

1 голос
/ 17 марта 2010

Это расширение ответа Винсента, включающее требование о том, чтобы группа длилась не менее 2 минут:

select event, tm_start, tm_stop
from (select event, min(when) tm_start, max(when) tm_stop
      from (select event,
                   when,
                   sum(discontinuity) over(order by when, event) continuous_group
              from (select event,
                           when,
                           case
                             when lag(event)
                              over(order by when, event) = event then
                              0
                             else
                              1
                           end discontinuity
                      from temp_stack ts))
     where event = 'ANOTHER'
     group by event, continuous_group)
where tm_stop - numtodsinterval(2, 'MINUTE') > tm_start;
1 голос
/ 17 марта 2010

это должно работать:

SQL> SELECT event, MIN(dt), MAX(dt) FROM (
  2     SELECT event, dt,
  3            SUM(discontinuity) over(ORDER BY dt, event) continuous_group
  4       FROM (SELECT event, dt,
  5                     CASE
  6                        WHEN lag(event) over(ORDER BY dt, event) = event THEN
  7                         0
  8                        ELSE
  9                         1
 10                     END discontinuity
 11                FROM DATA)
 12     )
 13   WHERE event = 'ANOTHER'
 14  GROUP BY event, continuous_group;

EVENT     MIN(DT)       MAX(DT)
--------- ------------- -------------
ANOTHER   20091109 1738 20091109 1751
ANOTHER   20091109 1721 20091109 1737

Примечание: события в 17:37 являются синхронными, и мой запрос произвольно поместил ДРУГОЕ событие в первый набор. Вы можете контролировать это поведение с помощью предложения ORDER BY аналитической функции.

0 голосов
/ 31 июля 2013

может быть немного поздно:)

SELECT
  event,
  min(dt) as dt_begin, max(dt) as dt_end
FROM 
(
select
  t.*,
  row_number()over(order by dt,rownum) -
  row_number()over(partition by event order by dt,rownum) as group_id
from vvp_tmp t
--order by dt
)
GROUP BY group_id,event
HAVING 24*60*(max(dt)-min(dt))>=2
ORDER BY dt_begin
0 голосов
/ 17 марта 2010

Это должно помочь вам начать. Обратите внимание, что если у вас есть несколько событий с одной и той же датой и временем (как в вашем примере), это недетерминировано. Если вы считаете, что это имеет смысл, вы можете добавить идентификатор в предложения ORDER BY как средство разрешения конфликтов.

SELECT * FROM (
SELECT event, id, date, time,
       lag(event) over (order by date, time) previous_event,
       lead(event) over (order by date, time) next_event
)
WHERE event='ANOTHER'
  AND ( event <> previous_event OR event <> next_event )
ORDER BY date, time
0 голосов
/ 17 марта 2010
SELECT  *
FROM    (
        SELECT  m.*, LEAD(event) OVER (ORDER BY date, time) AS ne, LAG(event) OVER (ORDER BY date, time) AS pe
        FROM    mytable m
        )
WHERE   event = 'ANOTHER'
        AND (ne <> event OR pe <> event)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...