英文:
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 |
详细信息:
plan_data
查询使用LEAD()
窗口函数:整个表通过PARTITION BY userId
分成分区,每个分区内的行按start_date
列排序。因此,对于给定分区中的当前行,LEAD()
函数会获取下一行的plan_name
。- 由于
plan_data
现在包含了旧计划和下一个计划的字段,我们可以简单地过滤出必要的行并计算更改计划的用户数。 - 切换日期是从 '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:
plan_data
query usesLEAD()
window function: the whole table is divided into partititions viaPARTITION BY userId
and the rows inside each partition are ordered bystart_date
column.<br>
So theLEAD()
function for a current row gets theplan_name
from the next row in a given partition.- 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. - 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 > 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;
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('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;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论