如何将滚动 7 天和 30 天的列添加到我每天在 SQL Server 中的不同登录次数中

Posted

技术标签:

【中文标题】如何将滚动 7 天和 30 天的列添加到我每天在 SQL Server 中的不同登录次数中【英文标题】:How to add rolling 7 and 30 day columns to my daily count of distinct logins in SQL Server 【发布时间】:2018-12-12 03:24:33 【问题描述】:

我有一半的查询输出每天登录我网站的不同用户总数。但我需要第三列和第四列来为我的用户显示滚动的周和月活动。

DECLARE @StartDate AS Date = DATEADD(dd,-31,GETDATE())

SELECT CAST(ml.login AS Date) AS Date_Login
,COUNT(DISTINCT ml.email) AS Total
FROM database.members_log AS ml
WHERE 1=1
AND ml.login > @StartDate
GROUP BY CAST(ml.login AS Date)
ORDER BY CAST(ml.login AS Date) DESC

如何补充我的代码以包含不同用户的 7 天和 30 天滚动计数

换句话说:在给定时间内(每日、过去 7 天、过去 30 天)登录的唯一用户数量

【问题讨论】:

您能否提供一个包含插入语句和预期输出的示例脚本 请定义不同用户的 7 天和 30 天滚动计数。 @GordonLinoff 刚刚在我的问题中定义了它 【参考方案1】:

不确定这是否是您想要的,但您可以使用窗口函数来滚动总计/计数。例如,如果您想保留按天计数的报告,但也按周和月滚动计数,您可以执行以下操作(使用中间 CTE):

declare @StartDate AS Date = DATEADD(day, -31, getdate());

WITH
    -- this is your original query, with the ISO week and month number added.
    members_log_aggr(login_date,  year_nbr, iso_week_nbr, month_nbr, email_count) AS
    (
        SELECT 
            CAST(ml.login AS Date),
            DATEPART(YEAR, ml.login),
            DATEPART(ISO_WEEK, ml.login),
            DATEPART(MONTH, ml.login),
            COUNT(DISTINCT ml.email) AS Total
        FROM members_log AS ml
        WHERE 
            ml.login > @StartDate
        GROUP BY 
            CAST(ml.login AS Date),
            DATEPART(YEAR, ml.login),
            DATEPART(ISO_WEEK, ml.login),
            DATEPART(MONTH, ml.login)
    )
-- here, we use window functions for a rolling total of email count.
SELECT *, 
    SUM(email_count) OVER 
    (
        PARTITION BY year_nbr, iso_week_nbr 
        ORDER BY login_date
        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
    ) AS count_by_week,
    SUM(email_count) OVER
    (
        PARTITION BY year_nbr, month_nbr
        ORDER BY login_date
        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
    ) as count_by_month
FROM members_log_aggr

给你这些数据:

+------------+----------+--------------+-----------+-------------+---------------+----------------+
| login_date | year_nbr | iso_week_nbr | month_nbr | email_count | count_by_week | count_by_month |
+------------+----------+--------------+-----------+-------------+---------------+----------------+
| 2018-12-12 |     2018 |           50 |        12 |           1 |             6 |              7 |
| 2018-12-13 |     2018 |           50 |        12 |           1 |             6 |              7 |
| 2018-12-14 |     2018 |           50 |        12 |           1 |             6 |              7 |
| 2018-12-15 |     2018 |           50 |        12 |           1 |             6 |              7 |
| 2018-12-16 |     2018 |           50 |        12 |           2 |             6 |              7 |
| 2018-12-19 |     2018 |           51 |        12 |           1 |             1 |              7 |
| 2019-01-13 |     2019 |            2 |         1 |           2 |             2 |              3 |
| 2019-01-21 |     2019 |            4 |         1 |           1 |             1 |              3 |
+------------+----------+--------------+-----------+-------------+---------------+----------------+

补充几点:

您的原始查询在您的WHERE 子句中有1=1。你不需要那个。 您的DATEADD 函数(或其他日期函数)中无需使用缩写。例如,DATEADD(DAY, -31, GETDATE()) 更清晰,与DATEADD(DD, -31, GETDATE()) 一样高效 将GETDATE() 替换为CURRENT_TIMESTAMP 可能是个好主意。它们是相同的函数,但 CURRENT_TIMESTAMP 是 SQL 标准。

【讨论】:

这正是我所需要的,并且喜欢最后的附加说明。我希望我每次都能收到这个反馈!【参考方案2】:

也许可以为此使用“条件聚合”(基本上只是在聚合函数中放置一个 case 表达式),例如

DECLARE @StartDate AS date = DATEADD( dd, -31, GETDATE() )

SELECT
    CAST( ml.login AS date )   AS Date_Login

  , COUNT( DISTINCT CASE
        WHEN CAST( ml.login AS date ) >= DATEADD( dd, -7, CAST( GETDATE() AS date ) ) THEN ml.email
    END )                      AS in_week

  , COUNT( DISTINCT ml.email ) AS Total
FROM dbo.members_log AS ml
WHERE 1 = 1
AND ml.login > @StartDate
GROUP BY
    CAST( ml.login AS date )
ORDER BY
    CAST( ml.login AS date ) DESC

但由于您已经过滤了过去 31 天,我不确定您所说的“滚动”周或“滚动”月是什么意思。

【讨论】:

我真正需要的是来自唯一用户的每日登录,过去 7 天和 30 天的唯一登录。除此之外,我还需要过去 30 天的历史数据【参考方案3】:

count(distinct) 相当棘手——尤其是对于滚动平均值。如果您真的在寻找一段时间内的唯一身份用户(而不仅仅是每日唯一身份访问者的平均值),那么我认为apply 可能是最简单的方法:

with d as (
      select cast(ml.login AS Date) AS Date_Login,
             count(distinct ml.email) AS Total
      from database.members_log ml
      where ml.login > @StartDate
      group by CAST(ml.login AS Date)
     )
select t.date_login, t.total, t7.total_7d, t30.total_30d
from t outer apply
     (select count(distinct ml2.email) as total_7d
      from database.members_log ml2
      where ml2.login <= dateadd(day, 1, t.date_login) and
            ml2.login > dateadd(day, -7, t.date_login)
     ) t7 outer apply
     (select count(distinct ml2.email) as total_30d
      from database.members_log ml2
      where ml2.login <= dateadd(day, 1, t.date_login) and
            ml2.login > dateadd(day, -30, t.date_login)
     ) t30
order by date_login desc;

日期算术是我对滚动平均值的最佳理解。它包括当天,但不包括前一天。

【讨论】:

为什么使用外部应用而不是交叉连接? @RogerSteinberg。 . .因为cross join 不起作用。有关联子句。

以上是关于如何将滚动 7 天和 30 天的列添加到我每天在 SQL Server 中的不同登录次数中的主要内容,如果未能解决你的问题,请参考以下文章

用 php 获取下一个第 15 天和/或第 30 天的日期?

在同一分组中添加具有上述所有行总和的列

如何将过去几天的数据从 Firebase 重新加载到 BigQuery?

为啥现在的电商平台数据统计, 都是滚动统计最近7天、最近15天、最近30天、最近90天的数据?

如何根据 3 个不同的列在 mysql 中选择行

2022-11-18:给定一个数组arr,表示连续n天的股价,数组下标表示第几天 指标X:任意两天的股价之和 - 此两天间隔的天数 比如 第3天,价格是10 第9天,价格是30 那么第3天和第9天的指