Найти временные интервалы в таблице в зависимости от значения столбца - PullRequest
0 голосов
/ 20 марта 2012

В моей базе данных postgreSQL 8.3.14 есть следующая таблица

     timestamp           status
2012-03-12 19:15:01        f
2012-03-12 19:15:02        f
2012-03-12 19:15:05        f
2012-03-12 19:17:01        t
-- END OF SLOT ONE (change from f to t)
2012-03-12 19:20:01        f
2012-03-12 19:25:01        f
2012-03-12 19:27:01        f
2012-03-12 20:15:01        t
-- END OF SLOT TWO (change from f to t)

Нет. Я хочу получить следующий результат:

  • длительность слота 1 (2012-03-12 19:17:01 - 2012-03-12 19:15:01)
  • длительность слота 2 (2012-03-12 20:15:01 - 2012-03-12 19:20:01)

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

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

1 Ответ

1 голос
/ 20 марта 2012

Если у вас есть современная версия PG, вы можете делать все, что хотите, используя оконные функции (в моем примере вместо меток времени у меня целые числа, но это не имеет значения): я работаю над неоконной версией функции...

db=> select * from test1;
 time | status
------+--------
1 | f
2 | f
3 | f
4 | t
5 | f
6 | f
7 | f
8 | t
9 | f
10 | t

(8 rows)

Вот запрос с оконными функциями:

 WITH a AS (
 SELECT time,rank() OVER (ORDER BY time) 
      FROM (
               SELECT status, time, lag(status,1)  OVER (ORDER BY time) AS ls
            FROM test1 
            ) AS x
             WHERE status AND NOT ls 
            -- select where the current status is true, the previous is false
       ),  -- a is now the endings of the slots
 b AS  (
     SELECT time, rank() OVER (ORDER BY time)
       FROM (
             SELECT  status, time, LAG(status,1)         
               OVER  (ORDER BY time)  AS ls
             FROM test1 
            ) AS x 
            WHERE (NOT status AND ls) OR (NOT status AND ls IS NULL) 
        )   -- b is now the beginning of the slots
    SELECT b.time as time1, a.time as time2 FROM a,b WHERE a.rank=b.rank;

  time1 | time2
------+------
1 |    4
5 |    8
9 |   10

Вот вариант запроса для PG без оконных функций (на самом деле он короче, но менее понятен)

  SELECT min(time) as time1, time2 FROM 
     (
         SELECT time, status,
          (
           SELECT time FROM test1 AS y
               WHERE y.time >= x.time
               ORDER BY (x.status = y.status)::int, y.time ASC LIMIT 1
          ) AS time2 
        FROM test1 AS x WHERE NOT status
     ) AS y GROUP BY y.time2 ORDER BY time2;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...