我正在尝试跟踪和显示用户每天在我的应用程序上连续发布的内容,但很难编写一个可靠运行并返回准确计数的查询。
我的应用程序有一个
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 的此类功能有点迷失,所以希望有一个简单的解决方案!
非常感谢。
这看起来像是孤岛和间隙问题以及间隙问题。
我已经按照问题中的要求创建了单个
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;