计算限制为 7 的用户的访问次数

Calculate the streaks of visit of users limited to 7

我正在尝试计算用户对应用程序的连续访问。我使用排名函数来确定每个用户维护的条纹。不过我的要求是条纹不能超过7条。

例如,如果用户连续 9 天访问该应用。他将有 2 次不同的连胜:一次是 7 次,一次是 2 次。

使用MaxCompute。它类似于 MySQL。

我有以下 table 名为 visitors_data:

user_id visit_date
murtaza 01-01-2021
john    01-01-2021
murtaza 02-01-2021
murtaza 03-01-2021
murtaza 04-01-2021
john    01-01-2021
murtaza 05-01-2021
murtaza 06-01-2021
john    02-01-2021
john    03-01-2021
murtaza 07-01-2021
murtaza 08-01-2021
murtaza 09-01-2021
john    20-01-2021
john    21-01-2021

输出应如下所示:

user_id streak
murtaza 7
murtaza 2
john    3
john    2

我能够通过以下查询获得条纹,但我无法将条纹限制为 7。

WITH groups AS (
    SELECT  user_id,
            RANK() OVER (ORDER BY user_id, visit_date) AS RANK,
            visit_date,
            DATEADD(visit_date, -RANK() OVER (ORDER BY user_id, visit_date), 'dd') AS date_group
    FROM visitors_data
    ORDER BY user_id, visit_date)

SELECT 
    user_id,
    COUNT(*) AS streak
FROM  groups 
GROUP BY 
    user_id,
    date_group
HAVING COUNT(*)>1
ORDER BY COUNT(*);

你可以事后分手。例如,如果您从来没有超过 21 个:

SELECT user_id, LEAST(streak, 7)
FROM (SELECT user_id, COUNT(*) AS streak
      FROM groups 
      GROUP BY user_id, date_group
      HAVING COUNT(*) > 1
     ) gu JOIN
     (SELECT 1 as n UNION ALL SELECT 2 as n UNION ALL SELECT 3 UNION ALL SELECT 4
     ) n
     ON streak >= n * 7
ORDER BY LEAST(streak, 7);

如果最长连胜的数字范围不确定,您可以使用递归 CTE 做类似的事情>

混合使用 window 函数和聚合:

SELECT user_id, COALESCE(NULLIF(MAX(counter) % 7, 0), 7) streak
FROM (
    SELECT *, COUNT(*) OVER (PARTITION BY user_id, grp ORDER BY visit_date) counter
    FROM (
      SELECT *, SUM(flag) OVER (PARTITION BY user_id ORDER BY visit_date) grp
      FROM (
        SELECT *, COALESCE(DATE_ADD(visit_date, INTERVAL -1 DAY) <> 
                  LAG(visit_date) OVER (PARTITION BY user_id ORDER BY visit_date), 1) flag
        FROM (SELECT DISTINCT * FROM visitors_data) t
      ) t
    ) t 
) t
GROUP BY user_id, grp, FLOOR((counter - 1) / 7)

参见demo

我的想法 运行 与 forpas 类似:

SELECT user_id, COUNT(*) streak
FROM 
(
   SELECT 
      user_id, streak, 
      FLOOR((ROW_NUMBER() OVER (PARTITION BY user_id, streak ORDER BY visit_date)-1)/7) substreak
   FROM 
   (
      SELECT 
         user_id, visit_date,
         SUM(runtot) OVER (PARTITION BY user_id ORDER BY visit_date) streak
      FROM (
         SELECT 
            user_id, visit_date, 
            CASE WHEN DATE_ADD(visit_date, INTERVAL -1 DAY) = LAG(visit_date) OVER (PARTITION BY user_id ORDER BY visit_date) THEN 0 ELSE 1 END as runtot
         FROM visitors_data
         GROUP BY user_id, visit_date
      ) x
   ) y
) z
GROUP BY user_id, streak, substreak

解释其工作原理;计算 运行s 连续记录的常用技巧是使用 LAG 检查之前的记录,如果只有例如一天之差则填 0,否则填 1。这意味着连续 运行 的第一条记录为 1,其余均为 0,因此该列最终看起来像 1,0,0, 0,1,0... SUM OVER ORDER BY 以“运行ning total”方式对其求和。这实际上意味着它形成一个计数器,每次遇到 运行 的开始时都会向上计数,因此 运行 4 天后跟一个间隙然后 运行 3 天看起来像 1 ,1,1,1,2,2,2 等,形成一个“连续 ID 号”。

如果将其送入按连续 ID 号分区的行编号,它会建立一个递增计数器,每次连续 ID 更改时都会重新启动。如果我们从这个中减去 1 所以它 运行s 从 0 而不是 1 那么我们可以将它除以 7 以获得我们的 9 长连胜的“子连胜 ID”,即 0,0,0,0, 0,0,0,1,1(依此类推。25 连胜将有 7 个零、7 个一、7 个二和 4 个三)

剩下的就是按用户、连胜 ID、子连胜 ID 分组并计算结果

在最后一组和统计数据之前看起来是这样的:

这应该让我们了解它是如何工作的