【问题标题】:How to calculate sliding Day by day count over the year SQL如何计算一年中的滑动日计数SQL
【发布时间】:2020-10-03 10:11:33
【问题描述】:

我必须计算过去两年(2019 年和 2020 年)每天的活跃用户总数。 我有日期、电子邮件和上次访问列。 如果 last_visit > current day - 90,则活动用户处于活动状态。 我遇到的第一个问题是我不知道如何告诉 SQL 我今天是什么日子。我尝试使用日期列,但它带来了错误和与以前相同的行数:

 WITH users_list as
  (SELECT SUBSTRING([agent_email], CHARINDEX('@', [agent_email])+1, LEN([agent_email])) AS DOMAIN,
          SUBSTRING(last_visit, 1, +10) as _date,
         VS.agent_email,
         VS.last_visit,
         vs.agent_license_type,
         vs.custom_templic
  FROM test.visitor AS VS
  WHERE VS.id NOT LIKE '%@rule.com'
    AND VS.agent_company NOT LIKE '%Rule%'
    AND last_visit> _date - 90
  GROUP BY VS.agent_email,
           VS.last_visit,
           vs.agent_license_type,
           vs.custom_templic

第二个问题我不知道如何计算 2019 年和 2020 年活跃用户的滑动总数。我用这个脚本试过:

SELECT _date, 
   count (agent_email)
   over(order by _date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as number_of_active_users
FROM users_list

但它也会带来错误。

【问题讨论】:

  • 请用您正在运行的数据库标记您的问题:mysql、oracle、sqlserver...?答案很可能是特定于供应商的。
  • 它是 Amazon Redshift。标签已添加。

标签: sql amazon-redshift


【解决方案1】:

很遗憾,Redshift 不支持 range 日期窗口框架规范。

您的示例代码实现了问题描述中没有的逻辑。本回答针对问题描述。

因此,另一种方法是跟踪用户何时在范围内而不是在范围内。首先要确定每个用户的范围,这是一个孤岛问题:

select test_email, min(last_visit) as active_start,
       max(last_visit) + interval '90 day' as active_end
from (select v.*,
             sum(case when prev_last_visit > last_visit - interval '100 day' then 0 else 1 end) over
                 (partition by test_email order by last_visit) as active_period
      from (select v.*,
                   lag(last_visit) over (partition by test_email order by last_visit) as prev_last_visit
            from test.visitor v
           ) v
     ) v

然后,利用这些信息,我们可以反透视以跟踪某人何时进入活动状态并离开。所以:

with actives as (
      select test_email, min(last_visit) as active_start,
             max(last_visit) + interval '90 day' as active_end
      from (select v.*,
                   sum(case when prev_last_visit > last_visit - interval '100 day' then 0 else 1 end) over
                     (partition by test_email order by last_visit) as active_period
            from (select v.*,
                         lag(last_visit) over (partition by test_email order by last_visit) as prev_last_visit
                  from test.visitor v
                 ) v
           ) v
      )
select dte,
       sum(inc) as change_on_day,
       sum(sum(inc)) over (order by dte rows between unbounded preceding and current row) as actives_on_day
from ((select test_email, active_start as dte, 1 as inc
       from actives
      ) union all
      (select test_email, active_end as dte, -1 as inc
       from actives
      )
     ) a
group by dte;

如果您想针对某个日期范围对此进行过滤,请使用附加子查询或 CTE,并在最外层查询中进行过滤。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-19
    • 2010-09-08
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多