2015-09-29 2 views
1

У меня есть этот movimentations стол:«Online» в записи каждые 5 минут

| id | user_id | in_time    | out_time   | 
------------------------------------------------------------- 
| 1 | 152  | 2015-08-28 15:43:00 | 2015-08-28 15:50:00 |   
| 2 | 123  | 2015-08-28 15:44:00 | 2015-08-28 15:55:00 |   
| 3 | 156  | 2015-08-28 15:50:00 | (null)    |   
| 4 | 211  | 2015-08-28 16:00:00 | 2015-08-28 16:17:00 |   
| 5 | 176  | 2015-08-28 16:21:00 | (null)    |  

Мне нужно знать, сколько пользователей были на сайте каждые пять минут (15:40, 15:45, 15:50 и так on) для построения графика. Это не та же проблема, которую они решили here, потому что здесь у меня есть in_time и out_time, что побудило меня подсчитать, сколько «онлайн» записей. Я знаю, как сделать это с помощью Исли Mutiple запросов:

SELECT * FROM movimentations WHERE out_time > '2015-08-28 15:40:00' AND in_time < '2015-08-28 15:40:00' UNION 
SELECT * FROM movimentations WHERE out_time > '2015-08-28 15:45:00' AND in_time < '2015-08-28 15:45:00' UNION 
SELECT * FROM movimentations WHERE out_time > '2015-08-28 15:50:00' AND in_time < '2015-08-28 15:50:00' UNION 
SELECT * FROM movimentations WHERE out_time > '2015-08-28 15:55:00' AND in_time < '2015-08-28 15:55:00'; 

Но, конечно, я ищу лучшее решение. Есть ли способ сделать это в одном запросе?

+0

возможным дубликатом [Группировки в интервал от 5 минут в диапазоне времени] (http://stackoverflow.com/questions/4342370/grouping -into-interval-of-5-minutes-in-time-range) –

+0

@SterlingArcher, к сожалению, это не так. Моя проблема кроется в том, что у меня есть in_time и out_time, и это не решено. – VSchettino

ответ

1

Этот запрос генерирует timepoints:

select t 
from generate_series('2015-08-28 15:40:00', '2015-08-28 16:30:00', '5m'::interval) t 

      t    
------------------------ 
2015-08-28 15:40:00+02 
2015-08-28 15:45:00+02 
2015-08-28 15:50:00+02 
2015-08-28 15:55:00+02 
2015-08-28 16:00:00+02 
2015-08-28 16:05:00+02 
2015-08-28 16:10:00+02 
2015-08-28 16:15:00+02 
2015-08-28 16:20:00+02 
2015-08-28 16:25:00+02 
2015-08-28 16:30:00+02 
(11 rows) 

Если вы cross join этот набор данных с movimentations и фильтров строк, вы будете получать:

with timepoints as (
    select t 
    from generate_series('2015-08-28 15:40:00', '2015-08-28 16:30:00', '5m'::interval) t 
    ) 
select t, count(*) 
from movimentations 
cross join timepoints 
where in_time <= t and coalesce(out_time, 'infinity') >= t 
group by 1 
order by 1; 

      t   | count 
------------------------+------- 
2015-08-28 15:45:00+02 |  2 
2015-08-28 15:50:00+02 |  3 
2015-08-28 15:55:00+02 |  2 
2015-08-28 16:00:00+02 |  2 
2015-08-28 16:05:00+02 |  2 
2015-08-28 16:10:00+02 |  2 
2015-08-28 16:15:00+02 |  2 
2015-08-28 16:20:00+02 |  1 
2015-08-28 16:25:00+02 |  2 
2015-08-28 16:30:00+02 |  2 
(10 rows) 

Этот результат не содержит пустойtimepoints. Если вы хотите иметь их, вы должны left join timespoints с результирующим набором:

with timepoints as (
    select t 
    from generate_series('2015-08-28 15:40:00', '2015-08-28 16:30:00', '5m'::interval) t 
    ) 
select t.t, c.count 
from timepoints t 
left join (
    select t, count(*) 
    from movimentations 
    cross join timepoints t 
    where in_time <= t and coalesce(out_time, 'infinity') >= t 
    group by 1 
    order by 1 
    ) c on c.t = t.t; 

      t   | count 
------------------------+------- 
2015-08-28 15:40:00+02 |  
2015-08-28 15:45:00+02 |  2 
2015-08-28 15:50:00+02 |  3 
2015-08-28 15:55:00+02 |  2 
2015-08-28 16:00:00+02 |  2 
2015-08-28 16:05:00+02 |  2 
2015-08-28 16:10:00+02 |  2 
2015-08-28 16:15:00+02 |  2 
2015-08-28 16:20:00+02 |  1 
2015-08-28 16:25:00+02 |  2 
2015-08-28 16:30:00+02 |  2 
(11 rows) 
+0

Это работает! Не знал этого «generate_series». Благодаря ;) – VSchettino