Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find the latest rating for each category for each customer

The data in the rating table looks like this:

StudentID Rating ScoreType Date
1 12 RAPID 2023-01-01
1 15 RAPID 2023-01-10
1 20 RAPID 2023-02-15
1 25 RAPID 2023-02-20
1 25 BLITZ 2023-03-01
1 33 BLITZ 2023-03-20
2 17 RAPID 2023-01-15
2 19 BLITZ 2023-02-06

What I am trying to build is like this:

StudentID RAPID_Rating RAPID_Games BLITZ_Rating BLITZ_Games Total Games
1 25 4 33 2 6
2 17 1 19 1 2

The data should be one row for each student

Column definitions of the expected output:

RAPID_Rating : Latest rating value based on date where ScoreType = 'RAPID'

RAPID_Games: Total number of RAPID games played by each student

BLITZ_Rating: Latest rating value based on date where ScoreType = 'BLITZ'

BLITZ_Games: Total number of BLIRZ games played by each student

Total Games: Total games played by each student

The SQL Code that I have tried:

select
    coalesce(a.StudentID,b.StudentID) as StudentID,
    a.rating as RAPID_Rating,
    RAPID_Games,
    b.rating as BLITZ_Rating,
    BLITZ_Games,
    RAPID_Games + BLITZ_Games as Total_Games
    
from 
(select 
    StudentID, 
    ScoreType,
    rating,
    count(rating) over(partition by StudentID,ScoreType) as RAPID_Games,
    row_number() over(partition by StudentID,ScoreType order by date desc) as RNUM
from rating 
    where ScoreType ='RAPID'
) a join (
    select 
    StudentID, 
    ScoreType,
    rating,
    count(rating) over(partition by StudentID,ScoreType) as BLITZ_Games,
    row_number() over(partition by StudentID,ScoreType order by date desc) as RNUM
from rating 
    where ScoreType ='BLITZ'
) b on a.StudentID = b.StudentID 
where a.RNUM = 1 and b.RNUM = 1

I have to do this calculation for another 2 categories then that will add up another 2 sub queries. Is there anyway to optimize this SQL code?

like image 378
Teja Goud Kandula Avatar asked Jan 24 '26 12:01

Teja Goud Kandula


1 Answers

We can use ROW_NUMBER along with conditional aggregation here:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY StudentID, ScoreType ORDER BY Date DESC) rn
    FROM rating
)

SELECT
    StudentID,
    MAX(Rating) FILTER (WHERE ScoreType = 'RAPID' AND rn = 1) AS RAPID_Rating,
    COUNT(*) FILTER (WHERE ScoreType = 'RAPID') AS RAPID_Games,
    MAX(Rating) FILTER (WHERE ScoreType = 'BLITZ' AND rn = 1) AS BLITZ_Rating,
    COUNT(*) FILTER (WHERE ScoreType = 'BLITZ') AS BLITZ_Games,
    COUNT(*) AS "Total Games"
FROM cte
GROUP BY StudentID
ORDER BY StudentID;
like image 174
Tim Biegeleisen Avatar answered Jan 26 '26 04:01

Tim Biegeleisen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!