Limit SQL query results by distinct column value - sql

I have an table with columns id, score, parent_id ordered by the score.
id
score
parent_id
5859
10
5859
2157043
9
5859
21064154
8
21064154
51992
7
51992
34384599
6
51992
1675761
5
1675761
3465729
4
3465729
401202
3
401203
1817458
2
1817458
I want to query all columns from this table with the same order but limit results at least 5 rows to meet the unique parent_id number equal to 5. As result, the parent_id only contains 5 ids: 5859, 21064154, 51992, 1675761, 3465729
Expected Results like:
id
score
parent_id
5859
10
5859
2157043
9
5859
21064154
8
21064154
51992
7
51992
34384599
6
51992
1675761
5
1675761
3465729
4
3465729

One other way you could accomplish this is to use lag to indicate when the id changes and then use a cumulative sum over a window then filtering accordingly:
select id, score, parent_id
from (
select *, Sum(diff) over(order by score desc)seq
from (
select *,
case when Lag(parent_id) over(order by score desc) = parent_id then 0 else 1 end diff
from t
)t
)d
where seq <= 5
order by score desc;

I understand that you want to retain rows that belong to the top 5 scoring parent_ids.
Although a sophisticated approach based on window functions might be possible here, here is one way to do it simply using a subquery:
select *
from mytable t
where parent_id in (
select top 5 parent_id
from mytable
group by parent_id
order by max(score) desc
)
order by score desc
If your data may have some score tied, consider adding option with ties to the subquery in order to guarantee a predictable result.

Related

Find the top 2 records for each key in a table [duplicate]

This question already has an answer here:
PostgreSQL: top n entries per item in same table
(1 answer)
Closed 7 months ago.
I have a list of results of player's scores in games, and I need to get the first two finishers for each game. LIMIT 2 works for the result set as a whole, but I need to limit it to 2 (or 1 if there is only one) per game.
Table being queried:
game_id
player_id
score
1
10
100
1
20
300
1
30
200
2
40
100
2
50
200
Desired results:
game_id
player_id
score
1
20
300
1
30
200
2
50
200
2
40
100
Using RANK() we can try:
WITH cte AS (
SELECT *, RANK() OVER (PARTITION BY game_id ORDER BY score DESC) rnk
FROM yourTable
)
SELECT game_id, player_id, score
FROM cte
WHERE rnk <= 2
ORDER BY game_id, score DESC;
Note that if there be the possibility of ties, then you might want to use DENSE_RANK instead of RANK. If ties are not a concern, then you could also use ROW_NUMBER instead of RANK.

How to get rank of a user from all users

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;

How to find the most frequently repeated column?

ID UserID LevelID
1 1 1
2 1 2
3 1 2
4 1 2
5 2 1
6 2 3
7 3 2
8 4 1
9 4 1
The query should return: LevelID: 1 (3 times) - the LevelID column that is most frequently repeated by different Users (UserID).
I have the following query:
SELECT LevelID, COUNT(LevelID) AS 'Occurrence'
FROM
(
SELECT DISTINCT * FROM
(
SELECT UserID, LevelID
FROM SampleTable
) cv
) levels
GROUP BY LevelID
ORDER BY 'Occurrence' DESC
Which returns:
LevelID Occurence
1 3
2 2
3 1
But it doesn't let me to add LIMIT 1; at the bottom to retrieve the first top row of the selection. What's wrong with the query?
There is no need for these several levels of nesting. Consider using aggregation, count(distinct ...), ordering the results and using a row-limiting clause to keep the top record only:
select top(1) levelID, count(distinct userID) cnt
from mytable
group by levelID
order by cnt desc
If you want to allow possible top ties, then use top (1) with ties instead of just top (1).

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;

SQL - Order by amount of occurrences

It's my first question here so I hope I can explain it well enough,
I want to order my data by amount of occurrences in the table.
My table is like this:
id Daynr
1 2
1 4
2 4
2 5
2 6
3 1
4 2
4 5
And I want it to sort it like this:
id Daynr
3 1
1 2
1 4
4 2
4 5
2 4
2 5
2 6
Player #3 has one day in the table, and Player #1 has 2.
My table is named "dayid"
Both id and Daynr are foreign keys, together making it a primary key
I hope this explains my problem enough, Please ask for more information it's my first time here.
Thanks in advance
You can do this by counting the number of times that things occur for each id. Most databases support window functions, so you can do this as:
select id, daynr
from (select t.*, count(*) over (partition by id) as cnt
from table t
) t
order by cnt, id;
You can also express this as a join:
select t.id, t.daynr
from table as t inner join
(select id, count(*) as cnt
from table
group by id
) as tg
on t.id = tg.id
order by tg.cnt, id;
Note that both of these include the id in the order by. That way, if two ids have the same count, all rows for the id will appear together.