PostgreSQL: найдите количество дней подряд до сих пор - PullRequest
5 голосов
/ 21 марта 2012

Учитывая кучу записей (которые представляют проверки в моем приложении) с полем отметки времени, что было бы хорошим способом определить текущую серию последовательных проверок?

Другими словами, если количество проверок отсортировано по убыванию, сколько записей осталось до тех пор, пока пользователь не пропустил день?

В настоящее время я использую эту технику:

SELECT distinct(uca.created_at::date) as created_at
    FROM user_challenge_activities as uca INNER JOIN user_challenges as uc
    ON user_challenge_id = uc.ID WHERE uc.user_id = #{user.id}
    order by (uca.created_at::date) DESC;

... где я приведу отметки времени регистрации к дате (в итоге, например, 2012-03-20), затем в коде просматриваю записи и увеличиваю счетчик до даты между записью и следующей записью больше 1 дня.

Тем не менее, этот подход кажется мне неуклюжим, и кажется, что Postgres преуспел бы в этом.

Так есть ли на самом деле лучший способ сделать это?

Ответы [ 2 ]

4 голосов
/ 21 марта 2012
with t as (
    SELECT distinct(uca.created_at::date) as created_at
    FROM user_challenge_activities as uca 
    INNER JOIN user_challenges as uc ON user_challenge_id = uc.ID 
    WHERE uc.user_id = #{user.id}
    )
select count(*)
from t
where t.create_at > (
    select d.d
    from generate_series('2010-01-01'::date, CURRENT_DATE, '1 day') d(d)
    left outer join t on t.created_at = d.d::date
    where t.created_at is null
    order by d.d desc
    limit 1
)
1 голос
/ 21 марта 2012

давайте попробуем это снова. будет генерировать только серии для необходимого диапазона:

SELECT count(distinct(uca.created_at::date)) FROM user_challenge_activities as uca
JOIN 
  (SELECT generate_series(max(series_date), 
                         (select max(user_challenge_activities.created_at) 
                          FROM user_challenge_activities), '1 day') as datez 
   FROM 
     (SELECT generate_series(min(user_challenge_activities.created_at::date),
                             max(user_challenge_activities.created_at), '1 day')::date
             as series_date 
      FROM user_challenge_activities) x
   LEFT JOIN user_challenge_activities 
     ON (user_challenge_activities.created_at::date = x.series_date)
   WHERE created_at IS NULL) d ON d.datez = uca.created_at::date
 INNER JOIN user_challenges as uc ON user_challenge_id = uc.ID 
 WHERE uc.user_id = #{user.id};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...