In my table i have team and points column and I want to get top 5 teams .Teams with same points should be grouped and consider as one of the ranks so if 5 teams are having same points then all should come as one of the rank and next suceeding records according to team points
TRY
SELECT DISTINCT(point), team
FROM tableTeam
ORDER BY points DESC LIMIT 5
SELECT team,
points,
(SELECT COUNT(*)
FROM teams t2
WHERE t2.points > t1.points) + 1 rank
FROM teams t1
ORDER BY points DESC
LIMIT 5
There's no window functions in MySQL, so you'll want to extract the rank in your scripts.
Also, if I'm making sense of your ranking criteria, you're actually interested in getting the top 5 teams plus any additional teams that might have the same number of points as that in the 5th rank.
If so, your limit should be applied to a subquery on the point criteria:
select name, points
from teams
where points >= (
select points
from teams
order by points desc
limit 1 offset 4
)
order by points desc, name
If not, a simple order by/limit will do:
select name, points
from teams
order by points desc, name
limit 5
Related
I have a DB Table user_points which contains user's points and I am trying to calculate ranking based on points. It is working fine for all users except users having 1 point.
If user have 1 point it is showing it's rank as 0 but it should display it's rank as last or in last numbers like: 12083 etc.
Higher points are, ranking should be higher as well. For example:
1000 points = rank 1
1 point = rank 1223
Following is the query.
SELECT id, mobileNo, points,
FIND_IN_SET( points, (SELECT GROUP_CONCAT( points ORDER BY points DESC )
FROM users_points )) AS rank
FROM users_points
WHERE mobileNo = '03214701777'
What should I change to fix it?
SELECT a.id, a.mobileNo, a.points,
IFNULL((SELECT COUNT(*) AS rank
FROM users_points b
WHERE b.points<a.points), 0)+1 as rank
FROM user_points a
WHERE a.mobileNo = '03214701777'
Seems to be what you are looking for. While it is still very innefficient it is better than your approach using FIND_IN_SET(). If you really want to use FIND_IN_SET() then you need to pad the scores to a consistent width and divide by the width+1 to get the rank.
Given a table with data with these columns (other columns too, but, these are the important ones):
gameid awayscore homescore
1 3 8
2 4 2
3 4 9
4 15 5
5 0 8
6 4 10
...
What I am looking for is to get the average margin of victory over the previous 3 games (assuming gameid is the order they were played), so, on game 6, it should be (6+8+10=24, average 8), on game 5 (8+10+5=23, average 7.666), etc. And then show the weeks where the 3-game average was the highest.
I tried to do it like this:
SELECT g.gameid,
(SELECT AVG(scores.ave) FROM (SELECT ABS(awayscore-homescore) ave FROM games gs
WHERE (gs.gameid<=g.gameid)
ORDER BY gameid DESC LIMIT 3) scores) margin
FROM `games` g
GROUP BY g.gameid
ORDER BY margin DESC
LIMIT 10;
But I get "Unknown column 'g.gameid' in 'where clause'", I assume because it is a subquery of a subquery(?), and it loses the reference? I am at a loss of how to structure it otherwise though to work correctly (if it is possible at all).
try this query
SELECT g.gameid,
(SELECT AVG(ABS(awayscore-homescore))
FROM games gs
WHERE (gs.gameid<=g.gameid)
AND (gs.gameid>g.gameid-3)
) margin
FROM `games` g
ORDER BY margin DESC
LIMIT 10;
sqlfiddle
UPDATE if you want to use gamedate (datetime) to order your game, you can create a game order (gorder) number based on this sort for everytime you select from games like the below query.
SELECT g.gameid,
(SELECT AVG(ABS(awayscore-homescore))
FROM
(SELECT awayscore,homescore,#rank:=#rank+1 as gorder
FROM games,(SELECT #rank:=0)r
ORDER BY gamedate ASC
)gs
WHERE (gs.gorder <= g.gorder)
AND (gs.gorder > g.gorder-3)
) margin
FROM (SELECT games.gameid,#rank2:=#rank2+1 as gorder
FROM games,(SELECT #rank2:=0)r2
ORDER BY gamedate ASC) g
ORDER BY margin DESC
LIMIT 10;
sqlfiddle
Let's say I have a table like this:
Player Score
A 5
B 4
A 3
B 2
A 1
B 1
A 2
B 3
A 4
B 5
I need an SQL query that will return the three highest scores per player in descending order "grouped" by player i.e.
Player Score
A 5
A 4
A 3
B 5
B 4
B 3
Very grateful for any pointers.
This is old-fashioned (read: basic sql) way of producing top-n per group. You might join the table to itself on group condition (here it is player) and pick records with higher score on right side; if there are three or less such records, the row is one of top n rows per group.
select player.player, player.score
from Player
left join Player p2
on p2.player = player.player
and p2.score > player.score
group by player.player, player.score
having count(distinct p2.score) < 3
order by 1, 2 desc
Alternative version you might check, using not exists:
select player, score
from player
where not exists
(
select p2.player
from Player p2
where p2.player = player.player
and p2.score > player.score
group by p2.player
having count(distinct p2.score) > 3
)
order by 1, 2 desc
This two versions differ in presentation of ties - while first one returns one row (by nature of group by) and needs to be joined back to original table to show all records, second one works directly from original table showing all data and ties at once.
You can find Demo at Sql Fiddle.
in SQL server:
select p.player, p.score
from PS p
where p.score in (select top 3 score from PS
where player = p.player order by score desc)
order by p.player asc, p.score desc
in MySql:
select p.player, p.score
from PS p
where p.score in (select score from PS
where player = p.player order by score desc limit 3)
order by p.player asc, p.score desc
I think what you are looking for can be found here:
http://www.sql-ex.ru/help/select16.php
Basically, the best solution uses the RANK function. Here is the example code from the site:
SELECT maker, model, type FROM
(
SELECT maker, model, type, RANK() OVER(PARTITION BY type ORDER BY model) num
FROM Product
) X
WHERE num <= 3
You would just need to modify the Partition By section to order by your score in descending order.
EDIT
Based upon the information that you will be using MySQL, you will need to make some modifications to the above query (which works with Microsoft SQL). You need to replace the RANK function with your own RANK implementation. It isn't that hard. Complete instructions can be found here:
http://thinkdiff.net/mysql/how-to-get-rank-using-mysql-query/
That will show you how to implement a counter that can give you a rank number.
Depending on what DBMS you use, you may be able to use row_number in some form
In SQL Server 2008 you can use
create table #player
( Player char, Score int )
insert into #player (Player, Score) Values
('A',5),('B',4),('A',3),('B',2),('A',1),('B',1),('A',2),('B',3),('A',4),('B',5)
select * from #player
select Player, Score from
(
select *, ROW_NUMBER() over(partition by Player order by Score desc) as rowNo
from #player
) as tmp
where tmp.rowNo <= 3
drop table #player
In my MySQL table Winners, I have a list of people who have won.
What I'd like to do is select a list of the names of 10 winners. So what I have right now is this:
SELECT name FROM Winners ORDER BY points DESC LIMIT 10
This returns the first 10 winners which is great.
But how can I make it (for example) return 10 winners, but starting at 20th place? Right now all I can think of is removing the LIMIT and programatically pulling out the 10 winners I want. But I'm sure there's an easier way.
SELECT name
FROM Winners
ORDER BY
points DESC
LIMIT 10 OFFSET 20
or just
SELECT name
FROM Winners
ORDER BY
points DESC
LIMIT 20, 10
SELECT name FROM Winners ORDER BY points DESC LIMIT 20, 10
I have an application that tracks high scores in a game.
I have a user_scores table that maps a user_id to a score.
I need to return the 5 highest scores, but only 1 high score for any specific user.
So if user X has the 5 highest scores on a purely numerical basis, I simply return the highest one and then the next 4 user scores.
I have tried to use:
SELECT user_id, score
FROM user_scores
ORDER BY score DESC
GROUP BY user_id
LIMIT 5
But it seems that MySQL drops any user_id with more than 1 score.
This should work:
SELECT user_id, MAX(score)
FROM user_scores
GROUP BY user_id
ORDER BY MAX(score) DESC
LIMIT 5
SELECT user_id, MAX(score) AS score
FROM user_scores
GROUP BY user_id
ORDER BY score DESC
LIMIT 5
Should do the job for you... though don't forget to create indexes...
You can't group by without a summary-function (SUM, COUNT, etc.)
The GROUP BY clause says how to group the SUMs or COUNTs.
If you simply want to break the long list into bunches with a common value, that's not SQL. That's what your application has to do.
Can you use the Distinct operator to say
SELECT DISTINCT(user_id), score
FROM user_scores
ORDER BY score DESC
LIMIT 5
didn't test so not sure if that will definitely work
Returning only the maximum score for a given user is something like the following.
SELECT user_id, max(score) FROM user_scores
GROUP BY user_id
I don't know whether it was a lack of caffeine or just brain explosion, but the answers here were so easy.
I actually got it working with this monstrosity:
SELECT s1.user_id,
(SELECT score FROM user_scores s2 WHERE s2.user_id = s1.user_id ORDER BY score DESC LIMIT 1) AS score
FROM user_scores s1
GROUP BY s1.user_id
ORDER BY s1.score DESC
LIMIT 5