每个月切换从计划 A 到计划 B 的用户数量。

huangapple go评论69阅读模式
英文:

Count users that switch from plan A to plan B every month

问题

我想每个月计算从**高级**计划切换到**基础**计划的所有用户。因此,表**plans**包含以下数据:

|   id     |    userId |   plan_name |       start_date       |
|----------|-----------|-------------|------------------------| 
|    1     |      20   |    ADVANCED | 2023-06-30 15:07:10.211|
|    2     |      20   |    ADVANCED | 2023-06-05 12:05:14.289|
|    3     |      40   |    BASIC    | 2023-05-31 20:05:13.324|
|    4     |      50   |    BASIC    | 2023-06-25 14:05:23.982| 
|    5     |      40   |    ADVANCED | 2023-05-03 11:05:10.234|
|    6     |      50   |    ADVANCED | 2023-06-01 11:05:10.234|

**期望结果:**

| num_users| monthly_changes|
|----------|----------------|
|    2     |    2023-06  	|
|    1     |    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(时间戳),以便我可以确定计划已经切换 - **高级 -> 基础**。对于此方面的任何见解或想法,我都非常感激。
英文:

I want to count all users that switch from ADVANCED plan to BASIC every month. So, the table plans contain the following data:

id userId plan_name start_date
1 20 ADVANCED 2023-06-30 15:07:10.211
2 20 ADVANCED 2023-06-05 12:05:14.289
3 40 BASIC 2023-05-31 20:05:13.324
4 50 BASIC 2023-06-25 14:05:23.982
5 40 ADVANCED 2023-05-03 11:05:10.234
6 50 ADVANCED 2023-06-01 11:05:10.234

The expected result:

num_users monthly_changes
2 2023-06
1 2023-05

Here's my query:

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;

The problem is how I can compare the start_date (in timestamp) of both plans, so I can figure out that there has been a switch of plans - Advanced -> Basic. Any insights or ideas are really appreciated.

答案1

得分: 2

以下是翻译好的内容:

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;

输出:

num_users year_month
1 2023-05
2 2023-06
1 2023-07

详细信息:

  1. plan_data 查询使用 LEAD() 窗口函数:整个表通过 PARTITION BY userId 分成分区,每个分区内的行按 start_date 列排序。因此,对于给定分区中的当前行,LEAD() 函数会获取下一行的 plan_name
  2. 由于 plan_data 现在包含了旧计划下一个计划的字段,我们可以简单地过滤出必要的行并计算更改计划的用户数。
  3. 切换日期是从 'ADVANCED' 切换到 'BASIC' 的日期。
英文:

DB fiddle with step-by-step queries

The query can be:

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;

Output:

num_users year_month
1 2023-05
2 2023-06
1 2023-07

Details:

  1. plan_data query uses LEAD() window function: the whole table is divided into partititions via PARTITION BY userId and the rows inside each partition are ordered by start_date column.<br>
    So the LEAD() function for a current row gets the plan_name from the next row in a given partition.
  2. As plan_data now contains both fields for old plan and next plan, we can simply filter the necessary rows and count the number of users with changed plans.
  3. Switch date is the date when the plan was changed from 'ADVANCED' to 'BASIC'.

答案2

得分: 1

为了识别从高级计划切换到基础计划的用户,您需要比较每个用户的当前计划与以前的计划。实现这一目标的一种方法是在“plans”表上使用自连接,您可以根据相同的用户但具有不同的开始日期将表与自身连接起来。然后,您可以比较当前记录和先前记录的plan_name,以检查是否发生了切换。

以下是已修改的查询,其中包括自连接,并添加了逻辑以计算每个月从高级到基础的切换用户:

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(公共表达式)用于获取从高级切换到基础的用户的信息。基于userId执行自连接,并确保当前计划的start_date大于先前计划的start_date。

在查询的主要部分中,我们使用plan_changes CTE来计算每个月切换计划的独特用户数量。我们使用TO_CHAR函数将日期格式化为“YYYY-MM”,以便在结果中更好地显示。

WHERE子句将结果过滤,仅包括当前_start_date和先前_start_date在同一月份的情况。

最终结果按月分组,并按月份的降序排序。

现在,该查询应该为您提供预期的结果,显示每月从高级切换到基础的用户数量。

英文:

To identify users who have switched from the ADVANCED plan to the BASIC plan, you need to compare the current plan with the previous plan for each user. One way to achieve this is by using a self-join on the "plans" table, where you can join the table with itself based on the same user but with different start dates. Then, you can compare the plan_name for the current and previous records to check if there has been a switch.

Here's the modified query that includes a self-join and adds logic to count the users who switched from ADVANCED to BASIC each month:

 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 &gt; p2.start_date
  WHERE p1.plan_name = &#39;BASIC&#39;
  AND p2.plan_name = &#39;ADVANCED&#39;
)
SELECT
  COUNT(DISTINCT userId) AS num_users,
  TO_CHAR(DATE_TRUNC(&#39;month&#39;, current_start_date), &#39;YYYY-MM&#39;) AS monthly_changes
FROM plan_changes
WHERE DATE_TRUNC(&#39;month&#39;, current_start_date) = DATE_TRUNC(&#39;month&#39;, previous_start_date)
GROUP BY DATE_TRUNC(&#39;month&#39;, current_start_date)
ORDER BY DATE_TRUNC(&#39;month&#39;, current_start_date) DESC;

Explanation of the query:

The plan_changes CTE (Common Table Expression) is used to get information about users who switched from ADVANCED to BASIC. The self-join is performed based on the userId and ensures that the current plan's start_date is greater than the previous plan's start_date.

In the main part of the query, we use the plan_changes CTE to count the number of distinct users who switched plans for each month. We use the TO_CHAR function to format the dates as "YYYY-MM" for better readability in the results.

The WHERE clause filters the results to include only those cases where the current_start_date and previous_start_date fall within the same month.

The final result is grouped by the month and ordered in descending order of months.

Now, the query should provide you with the expected result, showing the number of users who switched from ADVANCED to BASIC each month.

答案3

得分: 0

以下是已翻译的代码部分:

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;
英文:

Try something along the lines of

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(&#39;month&#39;,start_date) as month
    FROM plans
)

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

huangapple
  • 本文由 发表于 2023年7月23日 17:06:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76747426.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定