2013-09-13 4 views
6

Я использую PostgreSQL 9.2.
У меня есть таблица, содержащая время выхода некоторых устройств из эксплуатации.Группа с плавающим диапазоном дат

+----------+----------+---------------------+ 
| event_id | device |   time  | 
+----------+----------+---------------------+ 
|  1 | Switch4 | 2013-09-01 00:01:00 | 
|  2 | Switch1 | 2013-09-01 00:02:30 | 
|  3 | Switch10 | 2013-09-01 00:02:40 | 
|  4 | Switch51 | 2013-09-01 03:05:00 | 
|  5 | Switch49 | 2013-09-02 13:00:00 | 
|  6 | Switch28 | 2013-09-02 13:01:00 | 
|  7 | Switch9 | 2013-09-02 13:02:00 | 
+----------+----------+---------------------+ 

Я хочу, чтобы строки, которые будут сгруппированы по разнице во времени +/- 3 минут, как это:

+----------+----------+---------------------+--------+ 
| event_id | device |   time  | group | 
+----------+----------+---------------------+--------+ 
|  1 | Switch4 | 2013-09-01 00:01:00 |  1 | 
|  2 | Switch1 | 2013-09-01 00:02:30 |  1 | 
|  3 | Switch10 | 2013-09-01 00:02:40 |  1 | 
|  4 | Switch51 | 2013-09-01 03:05:00 |  2 | 
|  5 | Switch49 | 2013-09-02 13:00:00 |  3 | 
|  6 | Switch28 | 2013-09-02 13:01:00 |  3 | 
|  7 | Switch9 | 2013-09-02 13:02:00 |  3 | 
+----------+----------+---------------------+--------+ 

Я пытался сделать это с помощью функции окна, но в пункте

[RANGE | ЧСТРОК] МЕЖДУ frame_start И frame_end, , где frame_start и frame_end могут быть одним из НЕОГРАНИЧЕННЫХ предшествующего значения ПРЕДЫДУЩЕГО текущего значения ROW СЛЕДУЮЩЕГО НЕОГРАНИЧЕННЫХ СЛЕДУЮЩИХ,

значения должно быть целым число выражения не содержащее какие-либо переменными, агрегатных функций, или окно функции

Итак, учитывая это, я не могу указать временной интервал. Теперь я сомневаюсь, что функция окна может решить мою проблему. Не могли бы вы помочь мне?

+1

Для уточнения вопроса, если у вас есть строка с временем = '00: 03: 40 'в приведенном выше примере, будет ли он иметь номер группы 2, а другие группы сдвинутся на +1? Попытка понять, что вы подразумеваете под +/- 3 минутой разницы –

ответ

5

SQL Fiddle

select 
    event_id, device, ts, 
    floor(extract(epoch from ts)/180) as group 
from t 
order by ts 

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

select 
    event_id, device, ts, 
    dense_rank() over(order by "group") as group 
from (
    select 
     event_id, device, ts, 
     floor(extract(epoch from ts)/180) as group 
    from t 
) s 
order by ts 

time - зарезервированное слово. Выберите другое имя столбца.

+0

Ницца и просто. Я предложу небольшое улучшение. –

1

SQLFiddle

with u as (
select 
    *, 
    extract(epoch from ts - lag(ts) over(order by ts))/ 60 > 180 or lag(ts) over(order by ts) is null as test 
from 
    t 
    ) 

    select *, sum(test::int) over(order by ts) from u 
1

Это лишь небольшое улучшение по сравнению с @Clodoaldo's basically good answer.

Чтобы получить последовательные номера группы:

SELECT event_id, device, ts 
     ,dense_rank() OVER (ORDER BY trunc(extract(epoch from ts)/180)) AS grp 
FROM tbl 
ORDER BY ts 
  • Использования ts вместо (частично) зарезервированного слова time хороший совет. Поэтому не используйте reserved wordgroup. Вместо этого используется grp.

  • Последовательные номера могут быть указаны без подзапроса.

  • Использовать trunc() вместо floor(). Оба хороши, trunc() - slightly faster.

0

http://www.depesz.com/2010/09/12/how-to-group-messages-into-chats/

следует использовать кадрирование.это пример из учебника

with 
    xinterval(val) as (select 2), 
    data(id, t) as 
    (
    values 

     (1000, 1), 
     (1001, 2), 
     (1002, 3), 

     (1000, 7), 
     (1003, 8) 

), 
    x(id, t, tx) as 
    (
    select id, t, 
     case (t - lag(t) over (order by t)) > xinterval.val 
     when true then t when null then t 
     end 
    from data natural join xinterval 
), 
    xx(id, t, t2) as 
    (
    select id, t, max(tx) over (order by t) from x 
) 
select id, t, text(min(t) over w) || '-' || text(max(t) over w) as xperiod 
from xx 
window w as (partition by t2) 
order by t 
+0

Может ли добавить часть ссылок в случае, если ссылка ушла в какой-то день. – surfmuggle

0

функции Make

CREATE OR REPLACE FUNCTION public.date_round (
    base_date timestamp, 
    round_interval interval 
) 
RETURNS TIMESTAMP WITHOUT TIME ZONE AS 
$body$ 
DECLARE 
    res TIMESTAMP; 
BEGIN 
    res := TIMESTAMP 'epoch' + (EXTRACT(epoch FROM $1)::INTEGER + EXTRACT(epoch FROM $2)::INTEGER/2) 
       /EXTRACT(epoch FROM $2)::INTEGER * EXTRACT(epoch FROM $2)::INTEGER * INTERVAL '1 second';    
    IF (base_date > res) THEN 
     res := res + $2; 
    END IF; 
    RETURN res; 
END; 
$body$ 
LANGUAGE 'plpgsql' 
STABLE 
CALLED ON NULL INPUT 
SECURITY INVOKER 
COST 100; 

И группа этой функции результата

SELECT t.* FROM (SELECT p.oper_date, date_round(p.oper_date, '5 minutes') as grp FROM test p) t GROUP BY t.grp 

Это легко :)

Смежные вопросы