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;
Related
I have a database of 750 vehicles, I would like to run a query where I select no more than 5 of cheapest vehicles for each make & model and include those in my results.
My table fields are fldYear, fldMake, fldModel, fldRetail etc.
For example I would like the output to include the 5 cheapest Dodge 200 vehicles from 25 in total, the 5 cheapest Honda Accords from 30 in total, the 5 cheapest Jeep Cherokees from 10 in total, and if there only 2 Volkswagon Jettas, to include them as well. In the above example my output would have a total of 17 records.
I have played around with Sorts and Group By but I can't seem to get the desired output.
Just use variables:
SELECT *
FROM (
SELECT *,
#row := if(fldMake = #make,
#row := #row + 1,
if(fldMake := #make, 1, 1)
) as row
FROM yourCars
CROSS JOIN ( SELECT #make := '', #row:=0 ) as vars
ORDER BY fldMake, fldRetail ASC
) as T
WHERE T.row <= 5
I think you should retrieve 5 cheapest vehicle from one brand and put it in array or object. Same for other brands and after retrieving all the required data you can merge them in new array.
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
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.
i've tried some other topics for this but couldn't get answers that meet my requirement so posting a new question. sorry bout this.
i'm trying to query on mysql to get a 'sum' data until it reaches the defined value. like
from my table 'purchase', for each 'sid' starting from the last row, i need sum of 'pqty' until the result equals a value from string (but to try i've given a certain value).
let me define with the rows from my table---
the rows for 'sid=1' from 'purchase' are like this---
date pqty prate pamt
2014/04/29 5 38000 190000
2014/05/04 1 38000 38000
2014/05/13 20 35000 700000
2014/05/19 1 38000 38000
from this row, starting from the last row i want to 'sum(pqty) until it reaches 19(for now). it is achieved from adding last 2 rows(for 19). and stop sum here and return valus or sum of 'pqty', 'prate' and 'pamt'. to achieve this i tried the following according to example found on this forum.
SELECT date, pqty, #total := #total + pqty AS total
FROM (purchase, (select #total :=0) t)
WHERE #total<19 AND sid = $sid ORDER BY date DESC
but it's not working for me. please guide me through this. also suggest something else if this is not the good technique for my purpose.
thankz in advance.....
Not 100% certain, but I think both of these work...
SELECT x.*, SUM(y.pqty) FROM purchase x
JOIN purchase y
ON y.date >= x.date
GROUP
BY x.date
HAVING 19 BETWEEN SUM(y.pqty)-x.pqty AND SUM(y.pqty)
OR 19 >= SUM(y.pqty);
SELECT a.*
FROM
( SELECT x.*, #i := #i+pqty i
FROM purchase x
, (SELECT #i:= 0) var
ORDER
BY x.date DESC
) a
WHERE 19 BETWEEN a.i-a.pqty AND a.i
OR 19 >= a.i;
Sorry for posting another question about mysql ranking but all questions and answers which I already looked didn't help me....
I have mysql table of user points. User can have more results. My goal is to get max result from user and its rank.
CREATE TABLE results
(`user_id` int, `points` int);
INSERT INTO results VALUES
(1,10),
(2,20),
(3,20),
(4,30),
(4,60),
(5,5),
(1,80);
So upper solution would be:
rank | user_id | points
1 1 80
2 4 60
3 3 20
3 2 20
4 5 5
The following query does the trick:
SET #rank=0;
SET #points=0;
SELECT #rank := IF(#points = a.points, #rank, #rank + 1) AS rank, a.user_id, #points := a.points AS points
FROM (
SELECT user_id, MAX(points) as points
FROM results
GROUP BY user_id
) a
ORDER BY a.points DESC;
I have also created an SQLFiddle of it so you can see that it works: http://sqlfiddle.com/#!2/7ba2f/12
Use a user defined variable to produce the rank when selecting from an aggregated aliased query that calculates the maximum for each user:
select
(#rank := ifnull(#rank, 0) + 1) as rank,
user_id,
points
from (select
user_id,
max(points) as points
from results
group by 1
order by 2 desc) x
FYI, a UDV starts out life as null, hence the ifnull() call.