我的目标
我试图跟踪和显示用户每天在我的应用程序上发布的连续记录,但很难编写一个可靠的查询,并返回一个准确的计数。
一些背景
我的应用程序有一个prompt
和一个post
表。用户可以为每个提示提交一个帖子(提示是每天创建的,所以每个用户每天一个帖子)。
简化后的prompt
表如下所示:
| ID|日期键|文本|
| --|--|--|
| 1 | 20240101 |这是一个示例提示。|
| 2 | 20240102 |下面是第二个提示。|
简化的post
表类似于:
| ID|内容|提示ID| authorId|
| --|--|--|--|
| 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
字符串
这似乎适用于下面的数据,但如果您添加一个新的“missed”提示(这将重置条纹),此查询仍将返回2(我想我明白为什么,但不确定如何更正它)。
我需要的是
我基本上需要从最新的提示符开始,然后沿着列表向下走,直到找到一个没有该用户帖子的提示符。
例如,此关联数据的条纹为2:
| ID|日期键|文本|发布内容|authorId|
| --|--|--|--|--|
| 1 | 20240104 |这是一个示例提示。|这是我的回应。| 90 |
| 2 | 20240103 |下面是第二个提示。|第二个回应。| 90 |
| 3 | 20240102 |第三个提示。|null| null|
| 4 | 20240101 |我的第四个提示。|第三次回应,但我错过了一天。| 90 |
功能性是最重要的,但如果它的性能也很好(prompt
可能有1000行,post
可能有数百万行,streak
可能达到1000行)。
我对PostgreSQL在这方面的能力有点困惑,所以希望有一个简单的解决方案!
小提琴:https://www.db-fiddle.com/f/4jyoMCicNSZpjMt4jFYoz5/11431
2条答案
按热度按时间i5desfxk1#
对于自然值级数的单个表,有更简单的解决方案。但是对于两个表的组合,以及(看似)任意的下一个
promptId
,我希望recursive CTE表现最好:字符串
fiddle的
绝对需要索引支持快速。
prompt("dateKey", id)
上有一个索引,post("authorId", "promptId")
上有一个索引。假设...
prompt."dateKey"
是date
类型(应该是这样)。相关:
DB设计
如果每天最多出现一次提示,可以考虑将日期(数据类型
date
!)作为prompt
表中的PK和post
表中的FK,这样可以使查询更加简单,请参阅:7kqas0il2#
这似乎是岛屿和差距问题和差距问题。
我已经按照问题中的要求为单个
authorid
(p.authorId = 90
)创建了查询。您可以删除连接条件以获取所有authorIds
的数据。解决方案是使用窗口函数如下:
字符串