SQL 如何在变化的时间范围内计算不同的 id

SQL how to count distinct id in changing time ranges

我想统计今天到昨天、今天到3天前、今天到5天前、今天到7天前、今天到15 天前,从今天到 30 天前。

我的数据 table 如下所示:

     user_id.  fd_id.  date
      1.        123a.  20201010
      1.        123a.  20201011
      1.        124a.  20201011
      ...

所需的结果格式如下:

    user_id    count_fd_id_1d  count_fd_id_3d ... count_fd_id_30d

具体来说,我知道我可以执行以下 6 次并将它们连接在一起(一些列绑定方法):

select user_id, count(distinct fd_id) as count_fd_id_1d
from table 
where date <= today and date >= today-1 (#change this part for different dates)

select user_id, count(distinct fd_id) as count_fd_id_3d
from table 
where date <= today and date >= today-3 (#change this part for different dates)
...

我想知道如何在没有 运行 6 次几乎相同的代码的情况下一次完成此操作。

您可以使用条件聚合:

select user_id,
    count(distinct case when date >= current_date - 1 day and date < current_date then fd_id end) as cnt_1d,
    count(distinct case when date >= current_date - 3 day and date < current_date then fd_id end) as cnt_3d,
    ...
from mytable
goup by user_id

您可以尝试使用日期表达式来设置您想要的范围。以上适用于全天,不包括当天。

如果 table 中的 date 列确实看起来像那样(不是 date/datetime 格式),我认为您需要使用 STR_TO_DATE() 来转换它到日期格式然后使用 DATEDIFF 检查日期差异。考虑这个示例查询:

SELECT user_id, 
       MAX(CASE WHEN ddiff=1 THEN cn END) AS count_fd_id_1d,
       MAX(CASE WHEN ddiff=2 THEN cn END) AS count_fd_id_2d,
       MAX(CASE WHEN ddiff=3 THEN cn END) AS count_fd_id_3d,
       MAX(CASE WHEN ddiff=4 THEN cn END) AS count_fd_id_4d,
       MAX(CASE WHEN ddiff=5 THEN cn END) AS count_fd_id_5d
FROM (SELECT user_id, 
             DATEDIFF(CURDATE(), STR_TO_DATE(DATE,'%Y%m%d')) ddiff, 
             COUNT(DISTINCT fd_id) cn
      FROM mytable
      GROUP BY user_id, ddiff) A
GROUP BY user_id;

目前,如果您仅使用直接减法来检查日期值,您将得到不正确的结果。例如:

*your current date value - how many days:
'20201220' - 30 = '20201190' <-- this is not correct.

*if you convert the date value and using the same subtraction:
STR_TO_DATE('20201220','%Y%m%d') - 30 = '20201190' <-- still get incorrect.

*convert date value then uses INTERVAL for the date subtraction:
STR_TO_DATE('20201220','%Y%m%d') - INTERVAL 30 DAY = '2020-11-20'
OR
DATE_SUB(STR_TO_DATE('20201220','%Y%m%d'),INTERVAL 30 DAY) = '2020-11-20'

*IF your date column is storing standard date format value, then omit STR_TO_DATE
'2020-12-20' - INTERVAL 30 DAY = '2020-11-20'
OR
DATE_SUB('2020-12-20',INTERVAL 30 DAY) = '2020-11-20'

查看更多 date manipulation in MySQL

对于这个问题,I made a fiddle做了一堆测试。