【问题标题】:Cohort Analysis using SQL (Snowflake)使用 SQL (Snowflake) 进行队列分析
【发布时间】:2021-03-23 01:35:47
【问题描述】:

我正在使用表 TRANSACTIONS 进行同期群分析。下面是表架构,

USER_ID              NUMBER,
PAYMENT_DATE_UTC     DATE,
IS_PAYMENT_ADDED     BOOLEAN

下面是一个快速查询,可查看 USER_ID 12345(一个示例)如何根据提供的日期过滤器通过不同的同类群组,

WITH RESULT(
SELECT
USER_ID,
TO_DATE(PAYMENT_DATE_UTC) AS PAYMENT_DATE,
SUM(CASE WHEN IS_PAYMENT_ADDED=TRUE THEN 1 ELSE 0 END) AS PAYMENT_ADDED_COUNT
FROM TRANSACTIONS
GROUP BY 1,2
HAVING PAYMENT_ADDED_COUNT>=1
ORDER BY 2
)
SELECT
COUNT(DISTINCT r.USER_ID),
SUM(r.PAYMENT_ADDED_COUNT)
FROM RESULT r
WHERE r.USER_ID=12345
AND (r.PAYMENT_DATE>='2021-02-01' AND r.PAYMENT_DATE<'2021-02-15')

此查询的时间范围(两周)的结果将是

| 1 | 55 |

对于所提供的日期过滤器,此 USER_ID 将被归类为普通用户群组(支付超过 10 次的用户)

如果在一天的时间范围内运行相同的查询,比如'2021-02-07',结果将是

| 1 | 10 |

对于所提供的日期过滤器,此 USER_ID 将被归类为偶尔用户群组(已进行 1 到 10 次付款的用户)

我有以下查询,可根据添加的付款总和将 USER_ID 分入两个不同的同类群组中,

WITH
ALL_USER_COHORT AS 
(SELECT
USER_ID,
SUM(CASE WHEN IS_PAYMENT_ADDED=TRUE THEN 1 ELSE 0 END ) AS PAYMENT_ADDED_COUNT
FROM TRANSACTIONS
GROUP BY USER_ID
),
OCASSIONAL_USER_COHORT AS 
(SELECT
USER_ID,
SUM(CASE WHEN IS_PAYMENT_ADDED=TRUE THEN 1 ELSE 0 END ) AS PAYMENT_ADDED_COUNT
FROM TRANSACTIONS
GROUP BY USER_ID
HAVING (PAYMENT_ADDED_COUNT>=1 AND PAYMENT_ADDED_COUNT<=10)
),
REGULAR_USER_COHORT AS 
(SELECT
USER_ID,
SUM(CASE WHEN IS_PAYMENT_ADDED=TRUE THEN 1 ELSE 0 END ) AS PAYMENT_ADDED_COUNT
FROM TRANSACTIONS
GROUP BY USER_ID
HAVING PAYMENT_ADDED_COUNT>10
)
SELECT
COUNT(DISTINCT ou.USER_ID) AS "OCCASIONAL USERS",
COUNT(DISTINCT ru.USER_ID) AS "REGULAR USERS"
FROM ALL_USER_COHORT au
LEFT JOIN OCASSIONAL_USER_COHORT ou ON au.USER_ID=ou.USER_ID
LEFT JOIN REGULAR_USER_COHORT ru ON au.USER_ID=ru.USER_ID
LEFT JOIN TRANSACTIONS t ON au.USER_ID=t.USER_ID
WHERE au.USER_ID=12345
AND TO_DATE(t.PAYMENT_DATE_UTC)>='2021-02-07'

理想情况下,USER_ID 12345 应根据提供的日期过滤器存储为“OCCASIONAL USERS”,但查询将其存储为“REGULAR USERS”。

【问题讨论】:

  • 您的偶然用户队列和常规用户队列 CTE 中没有日期过滤器。您拥有的 where 语句过滤器按照 sql 执行的顺序发生在连接操作之后。为什么不使用日期过滤器对一个 CTE 中的每个 user_id 求和,然后用另一个定义您的存储桶的 case 语句包装该 CTE?
  • 向 CTE 添加日期过滤器会使每行的 PAYMENT_ADDED_COUNT 为 1...因为 USER_ID 只为给定日期付款...所以当我过滤一段时间一天之内,USER_ID 一直被归为 OCCASIONAL USERS
  • 我不明白你用 CASE 语句包装 CTE 是什么意思

标签: sql group-by aggregate-functions snowflake-cloud-data-platform common-table-expression


【解决方案1】:

对于初学者,您可以像这样删除 CTE 的冗余:

WITH all_user_cohort AS (
    SELECT
        USER_ID,
        SUM(IFF(is_payment_added=TRUE, 1,0)) AS payment_added_count
    FROM transactions
    GROUP BY user_id
), ocassional_user_cohort AS (
    SELECT * FROM all_user_cohort
    WHERE PAYMENT_ADDED_COUNT between 1 AND 10
), regular_user_cohort AS (
    SELECT * FROM all_user_cohort
    WHERE PAYMENT_ADDED_COUNT > 10
)
SELECT
COUNT(DISTINCT ou.user_id) AS "OCCASIONAL USERS",
COUNT(DISTINCT ru.user_id) AS "REGULAR USERS"
FROM all_user_cohort AS au
LEFT JOIN ocassional_user_cohort ou ON au.user_id=ou.user_id
LEFT JOIN regular_user_cohort ru ON au.user_id=ru.user_id
LEFT JOIN transactions t ON au.user_id=t.user_id
WHERE au.user_id=12345
AND TO_DATE(t.payment_date_utc)>='2021-03-01'

但是你遇到这个问题的原因是你一直在做属于你的事情。

您想要的是将日期过滤器移至all_user_cohort,而不是在您可以将满足需要的行数相加时制作表格。

WITH all_user_cohort AS (
    SELECT
        USER_ID,
        SUM(IFF(is_payment_added=TRUE, 1,0)) AS payment_added_count
    FROM transactions
    WHERE TO_DATE(payment_date_utc)>='2021-03-01'
    GROUP BY user_id
)   
SELECT
    SUM(IFF(payment_added_count between 1 AND 10, 1,0)) AS "OCCASIONAL USERS"
    SUM(IFF(payment_added_count > 10, 1,0)) AS "REGULAR USERS"
FROM transactions 
WHERE au.user_id=12345

也可以采取不同的方式,如果这更符合您的要求,出于其他原因。

WITH all_user_cohort AS (
    SELECT
        USER_ID,
        SUM(IFF(is_payment_added=TRUE, 1,0)) AS payment_added_count
    FROM transactions
    WHERE TO_DATE(payment_date_utc)>='2021-03-01'
    GROUP BY user_id
), classify_users AS (
    SELECT user_id
        ,CASE 
            WHEN payment_added_count between 1 AND 10 THEN 'OCCASIONAL USERS'
            WHEN payment_added_count > 10 THEN 'REGULAR USERS'
            ELSE 'users with zero payments'
        END AS classified
    FROM all_user_cohort
)
SELECT classified
    ,count(*)
FROM classify_users
WHERE user_id=12345
GROUP BY 1 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-08
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    相关资源
    最近更新 更多