Home > front end >  SQL Query Sequential Month Logins
SQL Query Sequential Month Logins

Time:05-31

I have the following SQL table

username Month
292 10
123 12
123 1
123 2
123 4
345 6
345 7

I want to query it, to get each username's login streak in Count of sequential Month. meaning the end result I am looking for looks like this :

username Streak
292 1
123 3
345 2

How can I achieve it ? taking into note the Month 12 --> Month 1 issue;

Appreciate your help;

CodePudding user response:

One way would be with a recursive CTE, like

WITH RECURSIVE cte (username, month, cnt) AS
(
 SELECT username, month, 1
 FROM test
 UNION ALL
 SELECT test.username, test.month, cte.cnt 1
 FROM cte INNER JOIN test
  ON cte.username = test.username AND CASE WHEN cte.month = 12 THEN 1 ELSE cte.month   1 END = test.month
)
SELECT username, MAX(cnt)
FROM cte
GROUP BY username
ORDER BY username

The idea is that the CTE (named cte in my example) recursively joins back to the table on a condition where the user is the same and the month is the next one. So for user 345, you have:

Username Month Cnt
345 6 1
345 7 1
345 7 2

The rows with cnt=1 are from the original table (with the extra cnt column hardcoded to 1), the row with cnt=2 is from the recursive part of the query (which found a match and used cnt 1 for its cnt). The query then selects the maximum for each user.

The join uses a CASE statement to handle 12 being followed by 1.

You can see it working with your sample data in this fiddle.

CodePudding user response:

The one shared by @EdmCoff is quite elegant.

Another one without recursive and just using conditional logic -

with data_cte as
(
select username, month_1,
case when (count(month_1) over (partition by username) = 1) then 1
when (lead(month_1) over (partition by username order by username) - month_1) = 1  OR (month_1 - lag(month_1) over (partition by username order by username)) = 1 then 1
when (month_1 = 12 and min (month_1) over (partition by username) =1) then 1
end cnt
from login_tab 
  )
  select username, count(cnt) from data_cte group by username

DB Fiddle here.

  • Related