Add second column to order by mysql in a group_concat - mysql

I have this query I made based on someone else question here.
SELECT *, FIND_IN_SET( score, ( SELECT GROUP_CONCAT( score ORDER BY score ASC) FROM EventPlayerResult WHERE eventId = 'EventTest0') ) AS position FROM EventPlayerResult WHERE eventId = 'EventTest0' ORDER BY position ASC LIMIT 10
It gives me a leaderboard for the top 10 players. But when I run it, if 2 players has the same score, I need it to filter by another column (energyLeft). So I tried to add , energyLeft DESC inside of my GROUP_CCONCAT but it doesnt change anything. im not familiar with group concat and find in set. So where should I add the logic to order by energyLeft after ordering by score.
I tried something like this :
SELECT *, FIND_IN_SET( score, ( SELECT GROUP_CONCAT( score ORDER BY score ASC, energyLeft DESC) FROM EventPlayerResult WHERE eventId = 'EventTest0') ) AS position FROM EventPlayerResult WHERE eventId = 'EventTest0' ORDER BY position ASC LIMIT 10

You should use the player and not the score inside GROUP_CONCAT() so that the players are ranked by score first and then by energyLeft.
Assuming there is a column like player_id in the table:
SELECT *,
FIND_IN_SET(
player_id,
(
SELECT GROUP_CONCAT(player_id ORDER BY score ASC, energyLeft DESC) FROM EventPlayerResult WHERE eventId = 'EventTest0'
)
) AS position
FROM EventPlayerResult
WHERE eventId = 'EventTest0'
ORDER BY position ASC LIMIT 10;

Related

Distinct entries from the set

I am using the below query on the above database table but unable to get the distinct value. Help will be appreciated
SELECT DISTINCT doctor_user_id, doctor_name, score, time_in_seconds FROM basket_game_master WHERE game_id='$game_id' ORDER BY score DESC, time_in_seconds ASC LIMIT $limit
The goal is to retrieve the doctor name with unique doctor_user_id who have more score with less time_in_seconds
You can use ROW_NUMBER():
SELECT doctor_user_id, doctor_name, score, time_in_seconds
FROM (SELECT bgm.*,
ROW_NUMBER() OVER (PARTITION BY doctor_user_id ORDER BY score DESC, time_in_seconds ASC) as seqnum
FROM basket_game_master bgm
WHERE game_id = ?
) mgm
WHERE seqnum = 1
ORDER BY score DESC, time_in_seconds ASC
LIMIT ?;
Note the use of ? for the parameters. Do not munge the query string with literal values! That poses a risk for SQL injections and for hard-to-debug syntax errors.

SQL query not returning distinct values

I have a game leaderboard comprised of 500 rows of data and I wrote a script to return that data and have no duplicate scores. However, I am getting duplicate scores returned to me. Here is my script.
SELECT DISTINCT
username, score,
FIND_IN_SET(score, (SELECT DISTINCT GROUP_CONCAT(score ORDER BY score DESC)
FROM TPS_STATS)) AS rank
FROM
TPS_STATS
ORDER BY
rank ASC
LIMIT 100;
An example of the duplicate results I am seeing is posted as an image.
If your version of MySql is 8.0 then you can use row_number():
SELECT
username,
score,
row_number() OVER (ORDER BY score desc, username) rn
FROM TPS_STATS
ORDER BY score desc, username
LIMIT 100
See the demo.
If it is lower:
select
username,
score,
(select count(*) from TPS_STATS where score > t.score) +
(select count(*) from TPS_STATS where score = t.score and username < t.username) + 1
rank
from TPS_STATS t
order by rank, username
limit 100
See the demo

SQL SCORE RANKING

I'm working with score ranking on my app for all user score. My problem is I don't know how to return one row for each stud_num.
My query:
SELECT * FROM score WHERE assess_type = 'professional' ORDER BY total_score DESC.
Result:
As you can see I have 3 stud_num and I only want one row per stud_num and the highest score of it.
You can use correlated query like this:
SELECT * FROM score t
WHERE t.assess_type = 'professional'
AND t.total_score = (select max(s.total_score)
from score s
where t.stud_num = s.stud_num)
group by stud_num
The option given by #sagi is good:
SELECT * FROM score t
WHERE t.assess_type = 'professional'
AND t.total_score = (select max(s.total_score)
from score s
where t.stud_num = s.stud_num)
group by stud_num
Another option would be to use an inner join and group by together.
The resulting query would become:
select * from score a
inner join (
SELECT stud_num, max(total_score) tscore FROM `score` group by stud_num) b
on a.stud_num = b.stud_num and total_score= tscore
group by a.stud_num
try it out at sqlfiddle
Use the MAX and GROUP BY functions like this:
SELECT score_id, stud_num, assess_type, total_item, MAX(total_score), average, date_taken
FROM score
WHERE assess_type = 'professional'
GROUP BY stud_num
ORDER BY 5 DESC
Here's my the ans:
SELECT score_id, stud_num, assess_type, total_item, MAX( total_score )
FROM score
WHERE assess_type = 'professional'
GROUP BY stud_num, total_item
ORDER BY MAX( total_score ) DESC

MySql sort within sorted results set

I have the following query which queries a table of sports results for the last 20 matches that involved a teams, returning goals conceeded in each of these matches.
SELECT *, `against` AS `goalsF` , `for` AS `goalsA`
FROM `matches` , `teams` , `outcomes`
WHERE (
`home_team_id`=7 AND `matches`.away_team_id = `teams`.team_id
OR
`away_team_id`=7 AND `matches`.home_team_id = `teams`.team_id
)
AND `matches`.score_id = `outcomes`.outcome_id
ORDER BY `against', `date` DESC
LIMIT 0 , 20
I want sort the results by goals conceeded and then within each group of goals conceeded by date so for example.
the first 4 results where goals conceded=1 in date order
then the next 3 might be results where conceded=2 in date order
I have tried ORDER by date,against - this gives me a strict date order
I have tried ORDER by against,date - this gives me matches beyond the last 20
Is it possible to do what I want to do?
Thanks everyone, I found this worked. This solution was posted by another user but then was removed, not sure why?
SELECT * FROM (
SELECT *, `against` AS `goalsF` , `for` AS `goalsA`
FROM `matches` , `teams` , `outcomes`
WHERE (
`home_team_id`=7 AND `matches`.away_team_id = `teams`.team_id
OR
`away_team_id`=7 AND `matches`.home_team_id = `teams`.team_id
)
AND `matches`.score_id = `outcomes`.outcome_id
ORDER by `goalsF`
LIMIT 0 , 20
) res
ORDER BY `date` DESC
If you want to limit by date, add the date range you are looking for into your WHERE clause and then order by the number of goals conceded.

Negative limit offset in mysql

I'm creating a high score server and one of the needed features is being able to retrieve high scores around the users current score. I currently have the following:
SELECT * FROM highscores
WHERE score >= ( SELECT score FROM highscores WHERE userID = someID )
ORDER BY score, updated ASC
LIMIT -9, 19
The only problem here is that the offset parameter of LIMIT can't be negative, otherwise I believe this would work dandy. So in conclusion, is there any trick / way to supply a negative offset to the LIMIT offset, or is there perhaps a better way to about this entirely?
You can either do a real pain in the butt single select query, or just do this:
(SELECT * FROM highscores
WHERE score <= ( SELECT score FROM highscores WHERE userID = someID )
ORDER BY score, updated ASC
LIMIT 9)
UNION
(SELECT * FROM highscores
WHERE score = ( SELECT score FROM highscores WHERE userID = someID ))
UNION
(SELECT * FROM highscores
WHERE score >= ( SELECT score FROM highscores WHERE userID = someID )
ORDER BY score, updated ASC
LIMIT 9)
I threw in a piece to grab the indicated user's score so it's in the middle of the list. Optional if you need it. Also, don't use SELECT *, use specific fields. Clarity is always preferable, and performance wise, * sucks.