如何在 postgresql 中计算用户的每日连续记录?

问题描述 投票:0回答:1

我的目标

我正在尝试跟踪和显示用户每天在我的应用程序上连续发布的内容,但很难编写一个可靠运行并返回准确计数的查询。

一些背景

我的应用程序有一个

prompt
和一个
post
表。用户可以为每个提示提交一篇帖子(提示每天都会创建,因此每个用户每天一篇帖子)。

简化后的

prompt
表如下所示:

id 日期键 文字
1 20240101 这是一个示例提示。
2 20240102 这是第二个提示。

简化后的

post
表类似于:

id 内容 提示ID 作者ID
50 这是我对提示的回应。 1 90
51 对同一提示的第二次响应。 1 91

当前查询

我尝试了几种不同的查询方法(使用

PARTITION BY
dense_rank()
等),但只能获得用户的最长连续记录。如果您有兴趣,我的疑问:

select distinct on (p."authorId") count(distinct "dateKey"::date) as "streak"
from (select p.*,
      dense_rank() over (partition by p."authorId" order by "dateKey"::date) as seq
      from post p
      join prompt pt on p."promptId" = pt.id
     ) p
join prompt pt on p."promptId" = pt.id
where p."authorId" = 90
group by p."authorId", "dateKey"::date - seq * interval '1 day'
order by p."authorId", streak desc

这似乎适用于以下数据,但如果您添加新的“错过”提示(这应该重置条纹),此查询仍将返回 2 (我想我明白为什么,但不确定如何纠正它)。

我需要什么

我基本上需要一些东西来从最新的提示开始,然后沿着列表向下查找,直到找到没有来自该用户的帖子的提示。

例如,此连接数据将具有 2 的条纹:

id 日期键 文字 帖子内容 作者ID
1 20240104 这是一个示例提示。 这是我的回应。 90
2 20240103 这是第二个提示。 第二个回应。 90
3 20240102 第三个提示。
4 20240101 我的第四个提示。 第三次回复,但我错过了一天。 90

功能最重要,但如果它也具有高性能那就太好了(

prompt
可能有 1000 行,
post
可能有数百万行,
streak
可能达到 1000)。

我对 postgres/sql 的此类功能有点迷失,所以希望有一个简单的解决方案!

非常感谢。

sql postgresql query-optimization window-functions
1个回答
0
投票

这看起来像是孤岛和间隙问题以及间隙问题。

我已经按照问题中的要求创建了单个

authorid
(
p.authorId = 90
) 的查询。您可以删除连接条件来获取所有
authorIds
的数据。

解决方案是使用窗口函数,如下所示:

select authorId, max(sm) from
(select t.*, 
        sum(case when is null then 1 end ) over (partition by p.authorId order by "dateKey"::date) as sm 
  from (select pt.*, p.*, 
               lag(p.promptId) over (partition by p.authorId order by "dateKey"::date) as prev_promptId
          from prompt pt
          left join post p on p.promptId = pt.id and p.authorId = 90) t ) t
group by authorId;
© www.soinside.com 2019 - 2024. All rights reserved.