我的目标

我正试图跟踪和显示用户在我的应用程序上的每日连续发帖,但我很难编写一个可靠工作并返回准确计数的查询.

一些背景

我的应用程序有一个prompt表和一个post表.用户可以 for each 提示提交一个帖子(提示是每天创建的,所以每个用户每天一个帖子).

简化后的prompt表如下所示:

id dateKey text
1 20240101 This is an example prompt.
2 20240102 Here is a second prompt.

简化后的post桌是这样的:

id content promptId authorId
50 This is my response to the prompt. 1 90
51 A second response to the same prompt. 1 91

当前查询

我try 了几种不同的查询方法(使用PARTITION BYdense_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

这似乎适用于下面的数据,但如果添加新的"Missing"提示(这应该会重置条纹),此查询仍将返回2(我认为我理解原因,但不确定如何纠正它).

我需要的是

我基本上需要一些东西开始在最新的提示,并向下列表,直到它发现一个提示没有来自该用户的帖子.

例如,此关联数据的条纹将为2:

id dateKey text postContent authorId
1 20240104 This is an example prompt. This is my response. 90
2 20240103 Here is a second prompt. A second response. 90
3 20240102 A third prompt. null null
4 20240101 My fourth prompt. A third response, but I missed a day. 90

功能性是最重要的,但如果它的性能也很好(prompt行可能有prompt0行,post行可能有数百万行,streak行可能达到prompt0行).

我对PostgreSQL处理这类事情的能力有点迷惑,所以希望有一个简单的解决方案!

菲德尔:https://www.db-fiddle.com/f/4jyoMCicNSZpjMt4jFYoz5/11431

推荐答案

对于带有自然值级数的单表,有更简单的解决方案.但对于两个表的组合以及(似乎)任意的Next promptId,我预计recursive CTE的表现最好:

WITH RECURSIVE cte AS (
   SELECT CURRENT_DATE AS the_day, p."authorId" AS author_id
   FROM   prompt pt
   JOIN   post  p ON p."promptId" = pt.id
   WHERE  pt."dateKey" = CURRENT_DATE
   AND    p."authorId" = 90  -- your author here!
   
   UNION ALL
   SELECT c.the_day - 1, p."authorId"   -- assuming no gaps in prompt!
   FROM   cte   c
   JOIN   prompt pt ON pt."dateKey" = c.the_day - 1
   JOIN   post  p  ON p."promptId" = pt.id
   WHERE  p."authorId" = c.author_id
   )
SELECT count(*)
FROM   cte;

fiddle

Absolutely requires index support to be fast.
Ideally, one index on prompt("dateKey", id), and one on post("authorId", "promptId").

假设...

  • ...我们查询一个给定的用户,
  • ...我们从"今天"开始
  • ...提示中没有空白-每天恰好有一个条目,
  • ...prompt."dateKey"date型的(它应该是).

相关:

数据库设计

If一天最多有一条提示,考虑使用日期(数据类型date!)作为表prompt的主键,使用表post的FK.允许更简单的查询.请参见:

Sql相关问答推荐

使用`lag()`获取上一个时间戳

当交叉联接3个或更多表时,实体框架中是否会传输冗余的行数据并占用数据库带宽?

对非RUST源代码字符串使用`stringify!`,例如SQL查询

如何根据计数和分组获取订单总数

对任何(数组)使用LIKE?

雅典娜嵌套Json提取液

在Oracle SQL中将列值转换为行

用于过滤嵌套对象或数组中的JSON数据的WHERE条件

查询每周数据(周一至周日),避免年度日期重叠

两个不同星期的销售额,不加成一行

将伪数据插入Postgres表

不存在记录的国外关键点

输出连续出现两次以上的行

在 SQL Server 中查找重复项

Postgresql 具有相似行为和模式行为的问题

SQL ORACLE - 查找连续天数

如何根据 SQL Server 中 1 条语句中 SELECT 的结果进行 INSERT 或 UPDATE

SQL for Smarties 类型问题:从表中 Select 记录,并对某些值进行分组

使用 JSON_BUILD_OBJ 从 Postgres 返回 JSON

如何在 SQL Server 中参数化 Select top 'n'