PostgreSQL:查找到现在为止的连续天数

Posted

技术标签:

【中文标题】PostgreSQL:查找到现在为止的连续天数【英文标题】:PostgreSQL: find number of consecutive days up until now 【发布时间】:2012-03-20 20:04:05 【问题描述】:

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

换句话说,按照签到时间降序排列签到,有多少记录直到用户错过一天?

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

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 擅长的事情。

那么实际上是否有更好的方法来实现这一点?

【问题讨论】:

在“当前连续签到”中定义“当前”。你是说包括今天在内的连胜纪录?还是只是最近的一次连胜? 啊,是的,包括今天在内的当前连续签到记录。本质上,包括今天在内,您已签到的连续天数 【参考方案1】:
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
)

【讨论】:

现在这有点太棒了!但是有一个问题:2010-01-01 的意义是什么? 我认为 CTE 需要用括号括起来:with t as ( ... ) @a_horse_with_no_name 已更正 你所说的“d.d”是什么意思?【参考方案2】:

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

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;

【讨论】:

以上是关于PostgreSQL:查找到现在为止的连续天数的主要内容,如果未能解决你的问题,请参考以下文章

查找连续的服务天数,中间没有休息日

如何查找两个日期之间的连续天数

如何在grafana elasticsearch中查找从现在到一个纪元时间的天数

在 DB2 中添加迄今为止的天数

查找逾期天数的 SQL 窗口函数

SQL 来确定不同的连续访问天数?