postgresql 统计每月从计划A切换到计划B的用户

pdkcd3nj  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(3)|浏览(95)

我想统计每个月从高级套餐切换到基本套餐的用户数。因此,表plans包含以下数据:
| 用户ID|计划名称|开始日期| start_date |
| --|--|--| ------------ |
| 二十个|高级|2023-06-30 15:07:10.211| 2023-06-30 15:07:10.211 |
| 二十个|高级|2023-06-05 12:05:14.289| 2023-06-05 12:05:14.289 |
| 四十|BASIC语言|2023-05-31 20:05:13.324| 2023-05-31 20:05:13.324 |
| 50人|BASIC语言|2023-06-25 14:05:23.982| 2023-06-25 14:05:23.982 |
| 四十|高级|2023-05-03 11:05:10.234| 2023-05-03 11:05:10.234 |
| 50人|高级|2023-06-01 11:05:10.234| 2023-06-01 11:05:10.234 |

预期结果:

| 月变化| monthly_changes |
| --| ------------ |
| 2023年6月| 2023-06 |
| 2023-05年| 2023-05 |
以下是我的查询:

SELECT COUNT(distinct userid) AS num_users, DATE_TRUNC('month',start_date) start_month
FROM plans
where plan_name ~ '\yADVANCED\y|\yBASIC\y'
GROUP BY DATE_TRUNC('month',start_date)
HAVING COUNT(userid) > 1 AND
SUM(
        CASE 
            WHEN ( plan_name ~ '\yADVANCED\y') OR ( plan_name ~ '\yBASIC\y') THEN 1
            ELSE 0
        END 
    ) > 1
ORDER BY DATE_TRUNC('month',start_date) DESC;

字符串
问题是我如何比较两个计划的start_date(在时间戳中),这样我就可以弄清楚计划-Advanced -> Basic的切换。任何见解或想法真的很感激。

jm81lzqq

jm81lzqq1#

**DB fiddle**逐步查询

查询可以是:

with plan_data as (
  select plan.*,
   LEAD(plan_name) OVER (PARTITION BY userId ORDER BY start_date) as next_plan
  from plan)

select count(distinct userid) as num_users, 
       to_char(plan_data.start_date, 'YYYY-MM') as year_month
from plan_data
where plan_data.plan_name = 'ADVANCED' and plan_data.next_plan = 'BASIC'
group by to_char(plan_data.start_date, 'YYYY-MM')
order by year_month;

字符串
输出量:
| 年月| year_month |
| --| ------------ |
| 2023-05年| 2023-05 |
| 2023年6月| 2023-06 |
| 2023-07| 2023-07 |
详细信息:

  1. plan_data查询使用LEAD()窗口函数:整个表通过PARTITION BY userId被划分为分区,并且每个分区内的行按start_date列排序。
    因此,当前行的LEAD()函数从给定分区的下一行获取plan_name
    1.由于plan_data现在包含 old plannext plan 两个字段,我们可以简单地过滤必要的行并计算更改计划的用户数量。
    1.切换日期是计划从“高级”更改为“基本”的日期。
cnwbcb6i

cnwbcb6i2#

要识别从高级计划切换到基本计划的用户,您需要将每个用户的当前计划与以前的计划进行比较。实现这一点的一种方法是在“plans”表上使用自联接,在该表中,您可以基于相同的用户但具有不同的开始日期来联接表本身。然后,您可以比较当前记录和以前记录的plan_name,以检查是否有切换。
下面是修改后的查询,它包括一个自连接,并添加了逻辑来计算每月从ADVANCED切换到BASIC的用户:

WITH plan_changes AS (
  SELECT
    p1.userId,
    p1.plan_name AS current_plan,
    p1.start_date AS current_start_date,
    p2.plan_name AS previous_plan,
    p2.start_date AS previous_start_date
  FROM plans p1
  LEFT JOIN plans p2
  ON p1.userId = p2.userId
  AND p1.start_date > p2.start_date
  WHERE p1.plan_name = 'BASIC'
  AND p2.plan_name = 'ADVANCED'
)
SELECT
  COUNT(DISTINCT userId) AS num_users,
  TO_CHAR(DATE_TRUNC('month', current_start_date), 'YYYY-MM') AS monthly_changes
FROM plan_changes
WHERE DATE_TRUNC('month', current_start_date) = DATE_TRUNC('month', previous_start_date)
GROUP BY DATE_TRUNC('month', current_start_date)
ORDER BY DATE_TRUNC('month', current_start_date) DESC;

字符串
查询说明:
plan_changes CTE(公共表表达式)用于获取有关从ADVANCED切换到BASIC的用户的信息。自联接基于userId执行,并确保当前计划的start_date大于前一计划的start_date。
在查询的主要部分,我们使用plan_changes CTE来计算每个月切换计划的不同用户的数量。我们使用TO_CHAR函数将日期格式化为“YYYY-MM”,以提高结果的可读性。
WHERE子句筛选结果,仅包括current_start_date和previous_start_date在同一个月内的情况。
最终结果按月份分组,并按月份降序排列。
现在,查询应该提供预期的结果,显示每月从ADVANCED切换到BASIC的用户数量。

hkmswyz6

hkmswyz63#

试着做一些

WITH plan_changes AS (
    SELECT userid,
           plan_name,
           start_date,
           LAG(plan_name) OVER (PARTITION BY userid ORDER BY start_date) as prev_plan,
           DATE_TRUNC('month',start_date) as month
    FROM plans
)

SELECT COUNT(DISTINCT userid) AS num_users,
       month AS monthly_changes
FROM plan_changes
WHERE plan_name = 'BASIC' AND prev_plan = 'ADVANCED'
GROUP BY month
ORDER BY month DESC;

字符串

相关问题