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 ~ 'yADVANCEDy|yBASICy'
GROUP BY DATE_TRUNC('month',start_date)
HAVING COUNT(userid) > 1 AND
SUM(
CASE
WHEN ( plan_name ~ 'yADVANCEDy') OR ( plan_name ~ 'yBASICy') 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.
3
Answers
Try something along the lines of
DB fiddle with step-by-step queries
The query can be:
Output:
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.So the
LEAD()
function for a current row gets theplan_name
from the next row in a given partition.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.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:
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.