PostgreSQL:查找到目前为止连续几天的数量

时间:2012-03-20 20:04:06

标签: sql postgresql date

给定一堆带有时间戳字段的记录(代表我的应用程序中的签到),什么是确定连续签到的当前条纹的好方法?

换句话说,通过签入时间降序排序的签到,在用户错过一天之前有多少条记录?

目前我正在使用这种技术:

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 个答案:

答案 0 :(得分:4)

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 :(得分:1)

让我们再试一次。只生成必要范围的系列:

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};