需要获得用户已经连续完成一个习惯的天数(Streak).这意味着最新的连胜(今天是倒退的),而不一定是他们最长的连胜.

插入以下日期后,我预计4号

  • 2023-09-14
  • 2023-09-15
  • 2023-09-16
  • 2023-09-17

此查询始终返回1,我在哪里出错了?

SELECT s.habit, MAX(s.streak) AS currentStreak
  FROM ( SELECT IF(@prev = o.habit_id AND o.date = @prevDate + INTERVAL 1 DAY
                  , @streak := @streak + 1
                  , @streak := 1
                ) AS streak
              , @prev := o.habit_id AS habit
           FROM ( SELECT t.habit_id
                       , DATE(t.created_at) AS `date`
                    FROM habit_progress_logs t
                   CROSS
                    JOIN (SELECT @prev := NULL, @prevDate := NULL, @streak := 1) i
                   GROUP BY t.habit_id, DATE(t.created_at)
                   ORDER BY t.habit_id, DATE(t.created_at)
                ) o
       ) s
  WHERE s.habit = 4
 GROUP BY s.habit

SQLFiddle with schema and data

推荐答案

您忘记了为每行设置@prevDate,并且返回的是最大条纹而不是最新条纹.

如果您使用的是MySQL&>=8.0,则可以使用window functions,而不是deprecated setting of user variables in expressions:

WITH streaks AS (
    SELECT
        habit_id,
        DATE(created_at) AS dt,
        DATE(created_at) - INTERVAL DENSE_RANK() OVER (PARTITION BY habit_id ORDER BY DATE(created_at) ASC) DAY AS grp
    FROM habit_progress_logs
    WHERE habit_id = 4
),
streaks2 AS (
    SELECT
        habit_id,
        grp,
        COUNT(DISTINCT dt) AS length,
        ROW_NUMBER() OVER (PARTITION BY habit_id ORDER BY grp DESC) AS rn
    FROM streaks
    GROUP BY habit_id, grp
)
SELECT habit_id, length AS currentStreak
FROM streaks2
WHERE rn = 1;

CTE个给出了日期序列分组,使用DENSE_RANK()(添加rnk用于说明):

habit_id dt rnk grp
4 2023-07-14 1 2023-07-13
4 2023-07-15 2 2023-07-13
4 2023-07-16 3 2023-07-13
4 2023-07-17 4 2023-07-13
4 2023-07-19 5 2023-07-14
4 2023-08-20 6 2023-08-14
4 2023-08-21 7 2023-08-14
4 2023-08-23 8 2023-08-15
4 2023-08-24 9 2023-08-15
4 2023-08-25 10 2023-08-15
4 2023-08-26 11 2023-08-15
4 2023-08-27 12 2023-08-15
4 2023-08-28 13 2023-08-15
4 2023-09-13 14 2023-08-30
4 2023-09-14 15 2023-08-30
4 2023-09-15 16 2023-08-30
4 2023-09-15 16 2023-08-30
4 2023-09-16 17 2023-08-30
4 2023-09-17 18 2023-08-30

第二个CTE进行分组,并添加ROW_NUMBER():

habit_id grp length rn
4 2023-08-30 5 1
4 2023-08-15 6 2
4 2023-08-14 2 3
4 2023-07-14 1 4
4 2023-07-13 4 5

如果您在使用MySQL<;8.0时遇到困难:

SELECT habit_id, COUNT(*) AS currentStreak
FROM (
  SELECT
    habit_id,
    dt,
    @grp := IF(@prevHabitId = habit_id AND dt = @prevDate + INTERVAL 1 DAY, @grp, @grp + 1) AS grp,
    @prevDate := dt,
    @prevHabitId := habit_id
  FROM (
    SELECT habit_id, DATE(created_at) AS dt
    FROM habit_progress_logs
    JOIN (SELECT @prevHabitId := NULL, @prevDate := NULL, @grp := 0) i
    WHERE habit_id = 4
    GROUP BY habit_id, dt
    ORDER BY habit_id, dt
  ) s
) t1
GROUP BY habit_id, grp
ORDER BY habit_id, grp DESC
LIMIT 1;

这是一张db<>fiddle

Mysql相关问答推荐

如何在逗号分隔字符串值中使用LEFT函数

MySQL问题难以将文本字符串转换为正确的日期格式

找出同一表中列A中的每个值在列B中出现的次数

返回包含某一列的分组最大值的行,说明列中的重复值

特定时间段内每个客户的运行总计

关于设置为 NOT NULL 时的 CHAR 默认值

根据 JOIN 结果计算列中的值?

在 MySQL 中使用非空条件 LAG() 函数

最后一个字母 '%n' 的 mysql SELECT 字符串不起作用

总行大小不超过 65535,但我得到行大小太大.所用表类型的最大行大小,不包括 BLOB,是 65535错误

巨大的未分区 MySQL 表问题

如何在 MySQL 中搜索多个列?

MySQL 5.6 DATETIME 不接受毫秒/微秒

MySQL:将日期时间插入其他日期时间字段

MySQL PHP - Select WHERE id = array()?

不是唯一的表/别名

让 MySQL 在 OSX 10.7 Lion 上运行

MySQL计算特定值的列

我可以在 PHP 中使用 PDO 创建数据库吗?

MySQL 错误 2014 的原因在其他无缓冲查询处于活动状态时无法执行查询