需要按月计算唯一交易,但忽略该 ID 第一次输入后 3 天发生的记录

Need to count unique transactions by month but ignore records that occur 3 days after 1st entry for that ID

我有一个只有两列的 table:User_ID 和 fail_date。每次有人的卡被拒绝时,他们都会登录 table,他们的卡会在 3 天后自动重试,如果他们再次失败,则会将另一个条目添加到 table。我正在尝试编写一个按月计算唯一失败次数的查询,因此我只想计算第一个条目,而不是 3 天重试次数(如果存在)。我的数据集看起来像这样

user_id  fail_date
222      01/01
222      01/04
555      02/15
777      03/31
777      04/02
222      10/11

所以我想要的输出是这样的:

month     unique_fails
jan       1
feb       1
march     1
april     0
oct       1 

我会在 Vertica 中 运行 这个,但我并不是在寻找回复中的完美语法。只是帮助解决这个问题,因为我真的想不出一种方法来让它发挥作用。谢谢!

您可以使用 lag() 获取每个用户之前的时间戳。如果当前时间戳和之前的时间戳相隔小于或恰好三天,则为跟进。将行标记为这样。然后您可以过滤以排除跟进。

它可能看起来像:

SELECT month,
       count(*) unique_fails
       FROM (SELECT month(fail_date) month,
                    CASE
                      WHEN datediff(day,
                                    lag(fail_date) OVER (PARTITION BY user_id,
                                                         ORDER BY fail_date),
                                    fail_date) <= 3 THEN
                        1
                      ELSE
                        0
                    END follow_up
                    FROM elbat) x
       WHERE follow_up = 0
       GROUP BY month;

我不太确定 Vertica 中的确切语法,因此它可能需要一些调整。我也不知道,如果 fail_date 实际上是某种 date/time 类型的变体或只是一个字符串。如果它只是一个字符串,date/time 特定函数可能无法处理它并且必须被替换,或者在将它传递给函数之前必须转换字符串。

如果数据跨越数年,您可能还希望在月份之外还包括年份,以将不同年份的月份分开。在内部 SELECT 添加一列 year(fail_date) year 并将 year 添加到列列表和外部 SELECT.

GROUP BY

您可以通过以下操作添加关于这是否是 "unique_fail" 的标志:

select t.*,
       (case when lag(fail_date) over (partition by user_id order by fail_date) > fail_date - 3
             then 0 else 1
        end) as first_failure_flag
from t;

那么,你想按月统计这个标志:

select to_char(fail_date, 'Mon'),  -- should aways include the year
       sum(first_failure_flag)
from (select t.*,
             (case when lag(fail_date) over (partition by user_id order by fail_date) > fail_date - 3
                   then 0 else 1
             end) as first_failure_flag
      from t
     ) t
group by to_char(fail_date, 'Mon')
order by min(fail_date)
  • Derived Table, determine the previous fail_date (prev_fail_date), for a specific user_id and fail_date, using a Correlated subquery.
  • 使用导出的table dt, Count 失败,如果当前fail_dateprev_fail_date之间的天数差为大于 3.
  • DateDiff() function alongside with If()函数用于判断情况,哪些不重复试。
  • Group By这个结果,可以使用MONTH函数。
  • 但是,数据可以来自多年,所以你需要将它们分开yearwise,这样你就可以也可以使用 YEAR 函数进行多级分组。

尝试以下(在 MySQL 中)- 您也可以了解其他 RDBMS:

SELECT YEAR(dt.fail_date) AS year_fail_date, 
       MONTH(dt.fail_date) AS month_fail_date, 
       COUNT( IF(DATEDIFF(dt.fail_date, dt.prev_fail_date) > 3, user_id, NULL) ) AS unique_fails 
FROM (
       SELECT  
         t1.user_id, 
         t1.fail_date, 
         (
          SELECT t2.fail_date 
          FROM your_table AS t2 
          WHERE t2.user_id = t1.user_id 
            AND t2.fail_date < t1.fail_date 
          ORDER BY t2.fail_date DESC 
          LIMIT 1
         ) AS prev_fail_date 
       FROM your_table AS t1 
     ) AS dt 
GROUP BY 
  year_fail_date, 
  month_fail_date 
ORDER BY 
  year_fail_date ASC, 
  month_fail_date ASC