I have the following QUERY and I need only the sum of the best 28 results
SELECT id_person, sum(points)
FROM ranking
WHERE id_open>=847 and id_club=2 and id_person!='91'
GROUP BY id_person
ORDER BY sum(points) desc, id_ranking
Each player (id_person), in this serie (id_open=847 or more), in this club (id_club=2) can play about 56 games, but only 28 best result counts for ranking, in other words, I'll despise 28 worst results.
** EDITED QUERY ** (id_ranking isn't necessary in ORDER BY)
SELECT id_person, sum(points)
FROM ranking
WHERE id_open>=847 and id_club=2 and id_person!='91'
GROUP BY id_person
ORDER BY sum(points) desc
If I am understanding correctly...
Your goal: Display players (i.e. id_person) in DESC order based on how many points that person makes in his/her best 28 games.
Here is a query that potentially does that:
SELECT id_person, sum(points) as s
FROM (
SELECT id_person,
points,
#rownum := if(#person = id_person, #rownum + 1, 1) as pointRank,
#person := id_person as dummy
FROM (SELECT id_person, points
FROM ranking
WHERE id_open >= 847 and id_club = 2 and id_person != '91'
ORDER BY id_person, points DESC
) as q1,
(SELECT #rownum := 0) as r,
(SELECT #person := '') as s
) as q2
WHERE pointRank <= 28
GROUP BY id_person
ORDER BY s DESC;
SQL Fiddle (Note: leaves out q1's WHERE clause for convenience)
Subquery q1 explanation:
Filters out rows based on id_open, id_club, and id_person.
Then, orders based on id_person (implicitly ASC) and points (explicitly DESC).
Finally, selects the id_person and points fields.
Note: MySQL Group By's are a little special - aggregates will work, but if selecting non-aggregates, a random row will be selected for the group by, not all rows (MYSQL-Group-By-returns-only-first-row)
Subquery q2 explanation:
Adds in rownum and person variables to keep track of ranking of game. (generate-column-containing-record-index-in-table)
Needs to use the (SELECT #rownum := 0) as r and (SELECT #person := '') as s to set the variables. (These variables could be set outside too.)
if(#person := id_person, #rownum + 1, 1) is necessary to reset the ranking of games per person.
Note: Important to initialize the person variable to an empty string, as opposed to 0. Not too sure why, but if you do not, then it will not reset the rownum variable correctly.
Overall query explanation:
All row numbers (i.e. pointRank) less than or equal to 28 (basically, the 28 best point scores per id_person) are kept.
After this filtering, each id_person will be grouped again.
Finally, the top 28 games' points will be summed up and labeled as s, and these pairs (id_person,s) will be ordered from highest to lowest.
Here is another StackOverflow question with a good article link inside (highly recommended read): (limit-within-group)
Note: I cannot guarantee this will work though, since I do not know what your table looks like. That information would help.
Related
I am trying to sum the nth highest rows.
I am calculating a cycling league table where 1st fastest rider at an event gets 50 points 2nd fastest 49 points and so on .... there are 10 events over the league but only a rider's 8 best results are used (this means a rider can miss up to 2 events without a catastrophic decent down the leader board)
first i need a table where each rider's results from all events in the league are grouped together and listed in order of highest points, and then a sequential number calculated so i can sum the 8 or less best results.
so i used this table select:
set #r := 0, #rn := 0 ;
SELECT
t.*,
#rn := if(#r = t.id_rider, #rn + 1, 1) as seqnum,
#r := t.id_rider as dummy_rider
from results as t
ORDER BY t.id_rider, t.points desc
where the table results is a view as below:
SELECT
a.id_rider,
b.id_event,
b.race_no,
b.id_race,
b.id_race_type,
b.`position`,
c.id_league,
(51 - b.`position`) AS points
FROM
wp_dtk_start_sheet a
JOIN wp_dtk_position_results b ON a.id_event = b.id_event AND a.race_no = b.race_no
JOIN wp_dtk_league_races c ON b.id_race = c.id_race
WHERE
c.id_league = 1
AND b.`position` IS NOT NULL
this does not work as the seqnum is 1 for all results. if i export the view table into excel and crate a test table with the same columns and data it works ok. i believe what is going wrong is that the table is not being sorted by ORDER BY t.id_rider, t.points desc before running through the variables
this reference: https://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/ states " This technique is pretty much non-deterministic, because it relies on things that you and I don’t get to control directly, such as which indexes MySQL decides to use for grouping"
this reference suggest trying to force the index to use id_rider so i tried:
set #r := 0, #rn := 0 ;
SELECT
a.id_rider,
c.id_league,
(51- b.`position`) as points,
#rn := if(#r = a.id_rider, #rn + 1, 1) as seqnum,
#r := a.id_rider as 'set r'
from wp_dtk_start_sheet as a force index (id_rider)
join wp_dtk_position_results as b on a.id_event = b.id_event and a.race_no = b.race_no
join wp_dtk_league_races as c on b.id_race = c.id_race
where c.id_league = 1 and b.`position` is not null
ORDER BY a.id_rider, points desc
this did not work i got seqnum =1 for all rows as before
my table structure is as below:
table a - wp_dtk_start_sheet
table b - wp_dtk_position_results
table c -wp_dtk_league_races
this stack overlow answer was also very helpfull but also has the same problem with it:
Sum Top 10 Values
can anyone help? perhaps i am going about this all the wrong way?
The solution is much more clear if you use window functions. This allows you to specify the order of rows within each group for purposes of row-numbering.
SELECT t.*
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY id_rider ORDER BY points DESC) AS seqnum
FROM results
) AS t
WHERE t.seqnum <= 8;
Support for window functions in MySQL was introduced in version 8.0, so you might have to upgrade. But it's been part of the MySQL product since 2018.
Bill's answer works brilliantly but I have also combined it into one statement as well, this is the combined select command:
Select
t.id_rider,
sum(points) as total
from
(SELECT
a.id_rider,
c.id_league,
(51- b.`position`) as points,
ROW_NUMBER() OVER (PARTITION BY id_rider ORDER BY points DESC) AS seqnum
from wp_dtk_start_sheet as a
join wp_dtk_position_results as b on a.id_event = b.id_event and a.race_no = b.race_no
join wp_dtk_league_races as c on b.id_race = c.id_race
where c.id_league = 1 and b.`position` is not null ) as t
where seqnum <= 8
group by id_rider
order by total desc
I want to count how many unique occurrences of an activity occurs in the table (FRIENDS) below. Then, I want to print the activities whom which their occurrences are not the maximum or minimum value of all occurrences.
***ID/Name/Activity***
1/James/Horse Riding
2/Eric/Eating
3/Sean/Eating
4/John/Horse Riding
5/Chris/Eating
6/Jessica/Paying
Ex:
Horse Riding occur 140 times
Playing occurs 170 times
Eating occurs 120 times
Walking occurs 150 times
Running occurs 200 times
The max occurrence here is Running, occurring 200 times, and the minimum occurrence here is Eating, occurring 120 times.
Therefore, I want to display
Horse Riding
Playing
Walking
In no particular order.
This is a code I have so far, but I keep getting a syntax error. When I don't get a syntax error, I get a "Every derived table must have its own alias error." I am new to SQL so I appreciate any advice I can get.
SELECT ACTIVITY, count(ACTIVITY) as Occurences FROM FRIENDS,
(SELECT MAX(Occur) AS Ma,MIN(Occur) AS Mi FROM (SELECT ACTIVITY, count(ACTIVITY) as Occur
FROM FRIENDS GROUP by City)) as T
GROUP BY City HAVING Occurences!=T.Ma AND Occurences!=T.Mi ORDER BY Occurences DESC
In MySQL 8.0, you can do this with aggregation and window functions:
select *
from (
select activity, count(*) cnt,
rank() over(order by count(*)) rn_asc,
rank() over(order by count(*) desc) rn_desc
from mytable
group by activity
) t
where rn_asc > 1 and rn_desc > 1
The subquery counts the occurences of each activity, and ranks them in both ascending and descending oders. All that is left to do is exclude the top and bottom records. If there are top ties (or bottoms), the query evicts them.
In earlier versions, an option is a having clause:
select activity, count(*) cnt
from mytable t
group by activty
having count(*) > (select count(*) from mytable group by activity order by count(*) limit 1)
and count(*) < (select count(*) from mytable group by activity order by count(*) desc limit 1)
I have a table of exam results. I need to get the record of a specific participant and get his/her ranking too.
for example, the participant with the participant_id 15 must have the ranking 3 amongst the total 4 records. so the result i am looking for would be:
id: 1
exam_id: 3
participant_id: 15
score: 343.23
ranking: 3
I know I can get the record and get the ranking through some PHP code, but I wonder if this is possible with Mysql queries.
I googled but did not really come up with a good solution. Any answer is highly appreciated!
This is the row_number function in postgresql and other databases which unfortunately isn't present in mysql.
This article http://www.mysqltutorial.org/mysql-row_number/ explains how to emulate it in mysql
To adapt the example from it
SET #row_number = 0;
SELECT
(#row_number:=#row_number + 1) AS rank, id, participant_id,exam_id, score
FROM
exams
LIMIT 5;
Following query will give you the required result
select t2.id,t2.exam_id,t2.exam_id,t2.participant_id,t2.score,t2.ranking from
(SELECT t.id,t.exam_id,t.participant_id,t.score,(#num:=#num+1) AS
ranking FROM table1 t cross join (SELECT #num:=0) AS dummy
ORDER BY t.score desc)as t2 where t2.participant_id=15;
You can run a query to create a separate table of results and then add condition to get the rank of required participant.
here is the query you can try
SELECT * FROM (SELECT re.*, #curRow := #curRow + 1 AS rank
FROM results re JOIN (SELECT #curRow := 0) r
WHERE 1 ORDER BY re.`score` DESC) AS tablea
WHERE participant_id=15
here is the result
id exam_id participant_id score rank
1 3 15 343.23 3
Here is my query:
SET #rank=0;
SELECT #rank := #rank +1 AS rank_id, name, SUM(points) AS points
FROM battle_points
WHERE category = 'test'
AND user_id !=0
GROUP BY user_id
ORDER BY points DESC;
I'd like to add a column rank based on the total points. With this query, the points are fine but the rank_id virtual column doesn't match up.
For example, the top user with the most points has rank 26, yet the rank_id column has a value of 24.
How do I matchup the rank_id column with the points column?
Note: while I am fully versed in PHP, I need a solution for MySQL only.
You are on the right path, but you need to put the main query in a subquery so that the ordering occurs before the rank calculation, like so:
SET #rank=0;
SELECT #rank := #rank +1 AS rank_id, mainQ.*
FROM (
SELECT name, SUM(points) AS points
FROM battle_points
WHERE category = 'test'
AND user_id !=0
GROUP BY user_id
ORDER BY points DESC
) AS mainQ
;
Edit: Qualified * to mainQ.*.
I’ve searched and I know this has been asked before but I am struggling to get my head around what I can / can’t do.
My cycling club records race results each time a rider has entered a race. Each result is awarded points - 50 for 1st, 49 for 2nd etc.
So the table looks like
resultid(pk) | riderid(fk) | leaguepts
1 1 50
2 2 49
3 3 48
4 1 50
5 2 42
6 3 50
7 4 30
...etc
I am trying to extract the sum of top 10 points awarded for each riderid from the results table.
(the actual database is a bit more complicated with a table for rider name / rider id and also a race table so we can display the results of each race etc but I just want to get the basic league table query working first of all)
So I want to extract the sum of the top 10 best scores for each rider. Then display each riders score, in a descending league table.
So far I’ve only had success using UNION ALL e.g.
SELECT sum(points) AS pts from
(
SELECT points from `results`
WHERE riderid = 1
ORDER BY points DESC
LIMIT 10
) as riderpts
UNION ALL
SELECT sum(points) AS pts from
(
SELECT points from `results`
WHERE riderid = 2
ORDER BY points DESC
LIMIT 10
) as riderpts
ORDER BY pts DESC
But there could be up to 90-odd riders who have registered at least one score so this query could get very big.
I found this which looks like it should work for me but doesn't. Sum top 5 values in MySQL I changed the column names for my table but it seems to sum all results, not the top 10 for each rider.
Alternatively I could just issue a query for each rider id. Not good I guess?
Subquerying is a problem because I can't limit on the inner query?
Run a job (manual or cron) to update the league table periodically and just display the table results?
Edit (not sure if this is the correct etiquette or I should start a new thread?). Gordon answered the question below but in the meantime I tried to work this out for myself using one of the links below. I could get results that returned the top 10 scores for each rider with the query below
set #riderid = '';
set #riderrow = 1;
select riderid, leaguepts, row_number
from
(
select
riderid,
leaguepts,
#riderrow := if(#riderid = riderid, #riderrow + 1, 1) as row_number,
#riderid := riderid as dummy
from wp_tt_results order by riderid, leaguepts desc
) as x where x.row_number <= 10;
BUT I can't see what I would need to do next to get the sum of top 10 results per riderid?
In MySQL, the easiest way to do this is probably to use variables:
SELECT riderid, sum(points)
FROM (SELECT r.*,
(#rn := if(#r = riderid, #rn + 1,
if(#r := riderid, 1, 1)
)
) as seqnum
FROM results r CROSS JOIN
(SELECT #r := 0, #rn := 0) as wnw
ORDER BY riderid, points DESC
) r
WHERE seqnum <= 10
GROUP BY riderid;