How to get rank of a user from all users - sql

I have table called summary_coins , By ranking of coins I am trying to get an user ranking
I have tried like below
SELECT
user_id,
sum(get_count),
rank() over (order by sum(get_count) asc) as rank
FROM summary_coins
WHERE user_id = 2
GROUP BY user_id
sample data , without user_id = 2 in where I am getting below list
user_id sum rank
44 2 1
13 4 2
57 4 2
47 4 2
11 5 5
2 5 5
My desire out put :
2 5 5
Here I am always getting ranking 1 for user ID 2 , But from list of user it should be rank 5.

You want to apply WHERE user_id = 2 late. RANK OVER is the last thing to happen in your query, but you want to apply the WHERE clause afterwards. In order to do this make your query a subquery you select from:
SELECT user_id, sum_count, rank
FROM
(
SELECT
user_id,
sum(get_count) AS sum_count,
rank() over (order by sum(get_count) asc) as rank
FROM summary_coins
GROUP BY user_id
) all_users
WHERE user_id = 2;

Related

Postgresql query to filter latest data based on 2 columns

Table Structure First
users table
id
1
2
3
sites table
id
1
2
site_memberships table
site_id
user_id
created_on
1
1
1
1
1
2
1
1
3
2
1
1
2
1
2
1
2
2
1
2
3
Assuming higher the created_on number, latest the record
Expected Output
site_id
user_id
created_on
1
1
3
2
1
2
1
2
3
Expected output: I need latest record for each user for each site membership.
Tried the following query, but this does not seem to work.
select * from users inner join
(
SELECT ROW_NUMBER () OVER (
PARTITION BY sm.user_id,
sm.created_on
), sm.*
from site_memberships sm
inner join sites s on sm.site_id=s.id
) site_memberships
ON site_memberships.user_id = users.user_id where row_number=1```
I think you have overcomplicated the problem you want to solve.
You seem to want aggregation:
select site_id, user_id, max(created_on)
from site_memberships sm
group by site_id, user_id;
If you had additional columns that you wanted, you could use distinct on instead:
select distinct on (site_id, user_id) sm.*
from site_memberships sm
order by site_id, user_id, created_on desc;

sql - select single ID for each group with the lowest value

Consider the following table:
ID GroupId Rank
1 1 1
2 1 2
3 1 1
4 2 10
5 2 1
6 3 1
7 4 5
I need an sql (for MS-SQL) select query selecting a single Id for each group with the lowest rank. Each group needs to only return a single ID, even if there are two with the same rank (as 1 and 2 do in the above table). I've tried to select the min value, but the requirement that only one be returned, and the value to be returned is the ID column, is throwing me.
Does anyone know how to do this?
Use row_number():
select t.*
from (select t.*,
row_number() over (partition by groupid order by rank) as seqnum
from t
) t
where seqnum = 1;

Creating a Rank Column with Repeated Indexes

I want to output the following table:
User | Country | RANK
------------------------------
1 US 3
1 US 3
1 NZ 2
1 NZ 2
1 NZ 2
1 JP 1
2 US 2
2 US 2
2 US 2
2 CA 1
What I have is the 'User' and 'Country' columns and want to create the RANK column.
I tried to use the function rank() like
rank() over (partition by User, Country order by ct desc) where ct is just the time of the event since epoch but instead of giving some repeated numbers like 33 222 1, it ranks inside the partition, giving me 12 123 1.
I also tried row_number() with no success.
If I use rank() over (partition by User order by country desc) it works, but how can I guarantee that it also ranks by ct?
Any clues on how to do that?
You are quite vague about the schema of your data. But assuming you have data that looks like this:
User Country Unix_time(epoch)
1 US 1437888888
1 NZ 1437666666
2 US 1437777777
2 NZ 1435555555
I think this will work but I can't test as I don't have hive on my laptop.
select c.*, b.rank
from my_table c
left outer join
(select user
, country
, rank() over (partition by user, order by unix_time desc) as rank
from
(select user, country, max(unix_time) as unix_time
from my_table group by user, country
) a
) b
on c.user=b.user and c.country=b.country
;
Basically I am selecting the maximum value for the time stamp associated with each user and country. This can then be ranked and joined to the original dataset.

SQL - Overall average Points

I have a table like this:
[challenge_log]
User_id | challenge | Try | Points
==============================================
1 1 1 5
1 1 2 8
1 1 3 10
1 2 1 5
1 2 2 8
2 1 1 5
2 2 1 8
2 2 2 10
I want the overall average points. To do so, i believe i need 3 steps:
Step 1 - Get the MAX value (of points) of each user in each challenge:
User_id | challenge | Points
===================================
1 1 10
1 2 8
2 1 5
2 2 10
Step 2 - SUM all the MAX values of one user
User_id | Points
===================
1 18
2 15
Step 3 - The average
AVG = SUM (Points from step 2) / number of users = 16.5
Can you help me find a query for this?
You can get the overall average by dividing the total number of points by the number of distinct users. However, you need the maximum per challenge, so the sum is a bit more complicated. One way is with a subquery:
select sum(Points) / count(distinct userid)
from (select userid, challenge, max(Points) as Points
from challenge_log
group by userid, challenge
) cl;
You can also do this with one level of aggregation, by finding the maximum in the where clause:
select sum(Points) / count(distinct userid)
from challenge_log cl
where not exists (select 1
from challenge_log cl2
where cl2.userid = cl.userid and
cl2.challenge = cl.challenge and
cl2.points > cl.points
);
Try these on for size.
Overall Mean
select avg( Points ) as mean_score
from challenge_log
Per-Challenge Mean
select challenge ,
avg( Points ) as mean_score
from challenge_log
group by challenge
If you want to compute the mean of each users highest score per challenge, you're not exactly raising the level of complexity very much:
Overall Mean
select avg( high_score )
from ( select user_id ,
challenge ,
max( Points ) as high_score
from challenge_log
) t
Per-Challenge Mean
select challenge ,
avg( high_score )
from ( select user_id ,
challenge ,
max( Points ) as high_score
from challenge_log
) t
group by challenge
After step 1 do
SELECT USER_ID, AVG(POINTS)
FROM STEP1
GROUP BY USER_ID
You can combine step 1 and 2 into a single query/subquery as follows:
Select BestShot.[User_ID], AVG(cast (BestShot.MostPoints as money))
from (select tLog.Challenge, tLog.[User_ID], MostPoints = max(tLog.points)
from dbo.tmp_Challenge_Log tLog
Group by tLog.User_ID, tLog.Challenge
) BestShot
Group by BestShot.User_ID
The subquery determines the most points for each user/challenge combo, and the outer query takes these max values and uses the AVG function to return the average value of them. The last Group By tells SQL to average all the values across each User_ID.

SQL Server Group by clause - Simple stuff

I have a table with questions and answers and sessionid.
Sometimes the same person (sessionid) will answer the same question more than 1 time, and that gets stored in the table.
The qapp_answer table content looks something like this:
Id, SessionID, QNumber, Qanswer
72 11 1 3
73 11 1 4
74 11 2 1
75 11 2 3
76 11 3 1
So, I only want each Qnumber to be displayed one time (so 3 rows in total), and basically just use their latest answer for display (Qanswer).
This is the code so far:
select Qnumber, Qanswer
from qapp_answers
where sessionid = 11
group by QNumber, Qanswer
And it returns 5 rows.
Should be simple, but i havent used SQL for years.
You can basically use ROW_NUMBER() which generates sequential number based on the group specified. The query belows group the records by QNumber and generates sequential number sorted by ID in descending order. The latest ID for every group has the value of 1 so you need to filter out records that has a generated value of 1.
SELECT ID, SessionID, QNumber, Qanswer
FROM
(
SELECT ID, SessionID, QNumber, Qanswer,
ROW_NUMBER() OVER (PARTITION BY QNumber ORDER BY ID Desc) rn
FROM tableName
WHERE SessionID = 11
) a
WHERE a.rn = 1
SQLFiddle Demo