如何将用户分为 90 天组

问题描述 投票:0回答:1

我希望根据用户购买商品的时间将他们分为不同的组。

用户上次购买商品已超过 90 天,新的群组就会开始。

我正在寻找的示例:

用户ID 日期 组中最小购买日期
1 123 2023-04-01 2023-04-01 1
2 123 2023-04-01 2023-04-01 1
3 123 2023-04-23 2023-04-01 1
4 123 2023-05-07 2023-04-01 1
5 123 2023-06-04 2023-04-01 1
6 123 2023-06-29 2023-04-01 1
7 123 2023-07-09 2023-07-09 2
8 123 2023-07-16 2023-07-09 2
9 123 2023-07-16 2023-07-09 2
10 123 2023-08-25 2023-07-09 2
11 123 2023-09-04 2023-07-09 2
12 123 2023-10-11 2023-10-11 3
13 123 2023-10-16 2023-10-11 3
14 123 2023-12-16 2023-10-11 3

第 1 组均共享相同的 min_purchase_date_in_group,因为所有购买日期均在首次购买后 90 天内。

第 7 行是新组的开始,因为距首次购买日期 (2023-04-01) 已超过 90 天,并且第 2 组内的所有日期均距首次购买日期 (2023-07-09) 90 天)为团体。

第 12 行开始一个新组,因为该组的首次购买日期 (2023-10-11) 距第 2 组的首次访问日期 (2023-07-09) 已超过 90 天。

我能够在 Python 中执行此操作,但我希望使用 SQL 来解决此问题。

如果日期相距较远,我可以通过检查前一行值并确定是否已经超过 90 天来解决此问题。

如果日期更接近,就像我的示例一样,我的查询会将同一组分配给所有 14 行。

这是我目前解决 min_purchase_date_in_group 问题的方法:

select 
  user_id,
  date,
  case
    when prev_date is null then date
    when prev_date is not null and datediff(day, first_value(date) over(partition by user_id order by date rows between unbounded preceding and unbounded following), date) < 90 then first_value(date) over(partition by user_id order by date rows between unbounded preceding and unbounded following)
  end as min_purchase_date_in_group
from purchases

它应用日期 2023-04-01 直到第 7 行,然后为空。我不确定如何使第 7 行变为 2023-07-09。

我也不确定如何确定组号。

sql database postgresql amazon-redshift gaps-and-islands
1个回答
0
投票

有一种用于“间隙和孤岛”的 SQL 技术 [在数字或日期序列中查找一系列缺失值(间隙)或一系列连续值(孤岛)],这与您的需求相关。

  • 首先,使用 LAG 函数对数据进行排序,以获取每行的前一个日期,同时按 user_id 进行分区

  • 然后根据日期之间的 90 天差距或之前日期的缺失来计算更改指标 (isGroupChange)。

  • 使用 SUM 窗口函数创建更改指示符的累积和,这会生成每组连续行的分组编号,直到下一个 isGroupChange。

--

WITH RankedPurchases
AS (
    SELECT *
        , LAG(min_purchase_date_in_group) 
              OVER (PARTITION BY user_id ORDER BY DATE) AS prev_min_purchase_date
    FROM purchases
    )
    , GroupChanges
AS (
    SELECT *
        , CASE 
            WHEN prev_min_purchase_date IS NULL OR DATE - prev_min_purchase_date > 90 THEN 1
            ELSE 0
            END AS isGroupChange
    FROM RankedPurchases
    )
    , GroupNumbering
AS (
    SELECT *
        , SUM(isGroupChange) OVER (
            PARTITION BY user_id ORDER BY DATE
            ) AS purchase_group
    FROM GroupChanges
    )
SELECT
      row
    , user_id
    , DATE
    , min_purchase_date_in_group
    , purchase_group
FROM GroupNumbering
ORDER BY DATE;
用户ID 日期 组中最小购买日期 购买_组
1 123 2023-04-01 2023-04-01 1
2 123 2023-04-01 2023-04-01 1
3 123 2023-04-23 2023-04-01 1
4 123 2023-05-07 2023-04-01 1
5 123 2023-06-04 2023-04-01 1
6 123 2023-06-29 2023-04-01 1
7 123 2023-07-09 2023-07-09 2
8 123 2023-07-16 2023-07-09 2
9 123 2023-07-16 2023-07-09 2
10 123 2023-08-25 2023-07-09 2
11 123 2023-09-04 2023-07-09 2
12 123 2023-10-11 2023-10-11 3
13 123 2023-10-16 2023-10-11 3
14 123 2023-12-16 2023-10-11 3

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.