Выберите отдельные строки вне временного интервала - PullRequest
3 голосов
/ 08 декабря 2011

Я пытаюсь использовать SQL для выбора отдельных записей данных на основе разницы во времени между одной записью и следующей. Это проще объяснить на примере:

Моя таблица данных имеет

Part    DateTime   
123     12:00:00
123     12:00:05
123     12:00:06
456     12:10:23
789     12:12:13
123     12:14:32

Я хотел бы вернуть все строки до тех пор, пока не будет допущено, что при наличии нескольких записей с одним и тем же номером "детали" я бы хотел получить только те, которые имеют разницу не менее 5 минут.

Запрос должен вернуть:

Part    DateTime   
123     12:00:00
456     12:10:23
789     12:12:13
123     12:14:32

Я использую следующий код:

SELECT data1.*, to_char(data1.scan_time, 'yyyymmdd hh24:mi:ss') 

FROM data data1 

where exists
(
    select * 

    from data data2

    where data1.part_serial_number = data2.part_serial_number AND 
    data2.scan_time + 5/1440 >= data1.scan_time 
    and data2.info is null
)

order by to_char(data1.scan_time, 'yyyymmdd hh24:mi:ss'), data1.part_serial_number

К сожалению, это не работает. Кто-нибудь знает, что я делаю неправильно или может предложить альтернативный подход?

Спасибо

Ответы [ 3 ]

3 голосов
/ 09 декабря 2011

Аналитические функции на помощь.

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

SQL> ed
Wrote file afiedt.buf

  1  with x as (
  2    select 123 part, timestamp '2011-12-08 00:00:00' ts
  3      from dual
  4    union all
  5    select 123, timestamp '2011-12-08 00:00:05'
  6      from dual
  7    union all
  8    select 123, timestamp '2011-12-08 00:00:06'
  9      from dual
 10    union all
 11    select 456, timestamp '2011-12-08 00:10:23'
 12      from dual
 13    union all
 14    select 789, timestamp '2011-12-08 00:12:13'
 15      from dual
 16    union all
 17    select 123, timestamp '2011-12-08 00:14:32'
 18      from dual
 19  )
 20  select part,
 21         ts,
 22         lead(ts) over (partition by part order by ts) next_ts
 23*   from x
SQL> /

      PART TS                              NEXT_TS
---------- ------------------------------- -------------------------------
       123 08-DEC-11 12.00.00.000000000 AM 08-DEC-11 12.00.05.000000000 AM
       123 08-DEC-11 12.00.05.000000000 AM 08-DEC-11 12.00.06.000000000 AM
       123 08-DEC-11 12.00.06.000000000 AM 08-DEC-11 12.14.32.000000000 AM
       123 08-DEC-11 12.14.32.000000000 AM
       456 08-DEC-11 12.10.23.000000000 AM
       789 08-DEC-11 12.12.13.000000000 AM

6 rows selected.

Как только вы это сделаете, вы можете создать встроенное представление и просто выбрать те строки, в которых следующая дата будет более чем через 5 минут после текущей даты.

SQL> ed
Wrote file afiedt.buf

  1  with x as (
  2    select 123 part, timestamp '2011-12-08 00:00:00' ts
  3      from dual
  4    union all
  5    select 123, timestamp '2011-12-08 00:00:05'
  6      from dual
  7    union all
  8    select 123, timestamp '2011-12-08 00:00:06'
  9      from dual
 10    union all
 11    select 456, timestamp '2011-12-08 00:10:23'
 12      from dual
 13    union all
 14    select 789, timestamp '2011-12-08 00:12:13'
 15      from dual
 16    union all
 17    select 123, timestamp '2011-12-08 00:14:32'
 18      from dual
 19  )
 20  select part,
 21         ts
 22    from (
 23      select part,
 24             ts,
 25             lead(ts) over (partition by part order by ts) next_ts
 26        from x )
 27   where next_ts is null
 28*     or next_ts > ts + interval '5' minute
SQL> /

      PART TS
---------- -------------------------------
       123 08-DEC-11 12.00.06.000000000 AM
       123 08-DEC-11 12.14.32.000000000 AM
       456 08-DEC-11 12.10.23.000000000 AM
       789 08-DEC-11 12.12.13.000000000 AM
1 голос
/ 09 декабря 2011

AFJ,

давайте предположим, что у нас есть новое поле, которое сообщает нам, существует ли предварительная запись для этой части в предыдущие 5 минут, а затем, взяв строки, для которых в этом поле установлено значение False, мы получили результат.

select  
  Part, 
  DateTime,
  coalesce(
    (select distinct 1
     from data ds
     where ds.Part = d.Part
       and ds.DateTime between d.DateTime and d.DateTime - 5/1440
    )
    , 0) as exists_previous 
from data d

Подзапрос проверяет, являются ли они строкой с одинаковой деталью в предыдущие 5 минут с интервалом

Результат должен быть:

Part    DateTime   exists_previous
123     12:00:00   0
123     12:00:05   1
123     12:00:06   1
456     12:10:23   0
789     12:12:13   0
123     12:14:32   0

теперь, фильтр, чтобы получить только строки с 0:

   select Part, DateTime from 
   (select  
      Part, 
      DateTime,
      coalesce(
        (select distinct 1
         from data ds
         where ds.Part = d.Part
           and ds.DateTime between d.DateTime and d.DateTime - 5/1440
        )
        , 0) as exists_previous 
    from data D
   ) T where T.exists_previous = 0

Отказ от ответственности: не тестировалось.

0 голосов
/ 08 декабря 2011

Это не было проверено, но, по сути, уловка заключается в группировке по частям И времени, разделенным на 5 минут (с минимальными затратами).

select part, min(scan_time)
from data
group by part, floor(scan_time/(5/1440))
order by scan_time;
...