I have a table which stores userids and their points in different categories. The number of users will keep changing. The points will also keep changing (like the points in stackoverflow). So a user who logins in will see a dashboard which says, for each of the 3 categories - You have 850 points, there are 950 users ahead of you. This is the query I have now -
WITH USERS AS (
SELECT COUNT(*) TOT
FROM user_pointS
)
SELECT ' You have ' || points_cat1 ||' points and there are '|| tot-rnk || ' ahead of you '
FROM (
SELECT ID,
points_cat1,
rank() OVER (ORDER BY points_cat1 DESC ) AS RNK
FROM user_pointS
) AS RANKED,
USERS
WHERE ID = 10
Is there a better way (performance-wise)? I will have to repeat this for the 3 columns?
Well, you can do this without the CTE:
SELECT ' You have ' || points_cat1 ||' points and there are '|| tot-rnk || ' ahead of you '
FROM (SELECT ID, points_cat1,
rank() OVER (ORDER BY points_cat1 DESC ) AS RNK ,
count(*) over () as TOT
FROM user_pointS
) RANKED
WHERE ID = 10;
You can do it for all three catagories at once:
SELECT ' You have ' || points_cat1 ||' points and there are '|| tot-rnk1 || ' ahead of you ',
' You have ' || points_cat2 ||' points and there are '|| tot-rnk2 || ' ahead of you ',
' You have ' || points_cat3 ||' points and there are '|| tot-rnk3 || ' ahead of you '
FROM (SELECT ID, points_cat1, points_cat2, points_cat3,
rank() OVER (ORDER BY points_cat1 DESC ) AS RNK ,
rank() OVER (ORDER BY points_cat2 DESC ) AS RNK1 ,
rank() OVER (ORDER BY points_cat3 DESC ) AS RNK2 ,
count(*) over () as TOT
FROM user_pointS
) RANKED
WHERE ID = 10;
You can probably replace the tot-rnk
with an inverse ranking:
rank() OVER (ORDER BY points_cat1 ASC ) AS RNK
but you would want to test that to be sure it gives you the results you expect.