Home > OS >  SQL - How to filter by date then compare column values with matching IDs
SQL - How to filter by date then compare column values with matching IDs

Time:08-05

Given this date example:

user_id total timestamp
1 19 2022-06-24 15:45:25
1 19 2022-05-23 12:48:34
1 0 2022-03-23 09:23:55
2 199 2022-06-24 18:51:42
2 0 2022-04-17 13:32:32
2 199 2022-03-18 19:14:15
3 0 2022-06-24 14:26:45
3 19 2022-04-22 03:39:08
3 0 2022-01-05 05:55:12
4 0 2022-06-24 12:59:25
5 19 2022-06-24 22:21:36
5 0 2022-05-18 07:08:41
6 199 2022-06-24 03:15:25

I need to get a COUNT of user_id's WHERE the for the most recent timestamp (for each user_id) the timestamp is "today" and the total in that row is > 0 AND for the 2nd most recent timestamp for that same user_id the total for that row is = 0.

Using the data above, the resulting COUNT is 2 (user_id 2 and 5 meet the criteria). This is also assuming "today" is 2022-06-24.

I have tried this query (below), which works for all scenarios except when a user_id has three or more timestamps. So in the example above, user_id 2 is not counted.

`

SELECT COUNT(table1.user_id)  
FROM table as table1, table as table2  
    WHERE table1.user_id IN (
        SELECT table1.user_id
        FROM table table1
        GROUP BY table1.user_id
        HAVING COUNT(*) = 2
     )
     AND date(table1.timestamp) = CURDATE()
     AND (table1.user_id = table2.user_id)
     AND date(table2.timestamp) < CURDATE()
     AND table2.total = 0
     AND table1.total > 0

`

CodePudding user response:

Use ROW_NUMBER to number a user's last row #1 and their penultimate row #2. Then aggregate and use conditional aggregation (CASE expression in the aggregation function) to check the values. Then aggregate again to count the matches.

select count(*)
from
(
  select user_id
  from
  (
    select
      t.*,
      row_number() over (partition by user_id order by timestamp desc) as rn
    from mytable t
  ) numbered
  where rn <= 2
  group by user_id
  having max(timestamp) = curdate()
  and max(case when rn = 1 then total end) > 0
  and max(case when rn = 2 then total end) = 0
) matches;

For old MySQL versions replace

row_number() over (partition by user_id order by timestamp desc) as rn

by

(
  select count(*) 
  from same_or_newer
  where same_or_newer.user_id = t.user_id
  and same_or_newer.timestamp >= t.timestamp
) as rn 
  • Related