Php Mysql Student Rank - mysql

I have this data in my database, all i want to do is to get the rank position and ties of student in a class based on the there total score , subject, session and term
i tried this but getting different position
SELECT d.username, c.ranks FROM
( SELECT total_score, #rank:=#rank+1 Ranks FROM
(SELECT DISTINCT total_score FROM
cbt_result a ORDER BY total_score DESC) t,
(SELECT #rank:= 0) r )
c INNER JOIN cbt_result d
ON c.total_score = d.total_score
WHERE term = 'first'
AND class_id ='$key'
AND subject_id = '$subkey'
AND username ='$student_username'
AND session_term = '$session_term_key'

Related

how can i get four last scores of each course in mysql? [duplicate]

This question already has answers here:
Get top n records for each group of grouped results
(12 answers)
Closed 3 years ago.
my database have four tables: student, course, stu_course, score.
columns for course table: id, name
columns for student table: id, firs_name, last_name, username, password
columns for stu_course table: id, stu_id, course_id
(stu_id and cours_id are foreign keys)
columns fir score table: id, stu_cours_id, score, date
(stu_cours_id is forein ksy)
My question is how can i get four last scores of each course in score table?
here is what i currently have:
SELECT s.first_name
, c.name
, sc.id
, k.score
, k.date
,
FROM student s
JOIN stu_course sc
ON sc.stu_id = s.id
JOIN course c
ON c.id = sc.course_id
JOIN score k
ON k.stu_course_id = sc.id
Thanks for your helps
In MySQL 8.0 (Maria DB >= 10.2), you could use window function ROW_NUMBER() to rank the scores of each course by descending date. Then, just filter out records with a rank higher than 4:
SELECT *
FROM (
SELECT student.first_name, course.name, stu_course.id, score.score, score.date,
ROW_NUMBER() OVER(PARTITION BY course.id ORDER BY score.date DESC) rn
FROM `student`
INNER JOIN stu_course ON stu_course.stu_id = student.id
INNER JOIN course ON course.id = stu_course.course_id
INNER JOIN score ON score.stu_course_id=stu_course.id
) x WHERE rn <= 4
In earlier versions of MySQL/MariaDB, a solution would be to use a correlated subquery:
SELECT
s.first_name,
c.name,
sc.id,
k.score,
k.date
FROM student s
JOIN stu_course sc ON sc.stu_id = s.id
JOIN course c ON c.id = sc.course_id
JOIN score k
ON k.stu_course_id = sc.id
AND (
SELECT COUNT(*) FROM score k1 WHERE k1.stu_course_id = k.stu_course_id AND k1.date > k.date
) <= 3
You can use an ORDER BY statement to sort your list (use order by desc to sort descending) then use LIMIT x to just show the first x results.
Effectively if you use ORDER BY DESC LIMIT x you'll see the bottom x results when sorted by your chosen column

SQL Rank Function with Group

I want to rank the total stats of a group of users and assign a rank variable to them.
I used this thread for the Rank variable.
This is my Query atm:
SELECT #rank := #rank + 1 AS rank
, SUM(stats.points) AS x
FROM
( SELECT #rank := 0 ) r
, groups
LEFT
JOIN user_group
ON groups.id = user_groups.clan
LEFT
JOIN stats
ON user_groups.user = stats.id
GROUP
BY groups.id
ORDER
BY x DESC
RANK | points
--------------
47 | 3400
1 | 2500
75 | 1200
As you can see the Sorting by Points works fine, but the Rank variable seems to just pick random values.
Can anyone find a way to assign the rank correctly?
Use a subquery for the aggregation and ordering:
SELECT id, sum_points, #rank := #rank + 1 AS rank
FROM (SELECT g.id, SUM(s.points) AS sum_points
FROM groups g LEFT JOIN
user_group ug
ON g.id = ug.clan LEFT JOIN
stats s
ON ug.user = s.id
GROUP BY g.id
ORDER BY sum_points DESC
) s CROSS JOIN
(SELECT #rank := 0) params;
This has been an issue in MySQL for a while -- variables don't work well with aggregation and ordering.
Note that in MySQL 8+, this is much more simply written as:
SELECT g.id, SUM(s.points) AS sum_points,
ROW_NUMBER() OVER (ORDER BY SUM(s.points) DESC) as rank
FROM groups g LEFT JOIN
user_group ug
ON g.id = ug.clan LEFT JOIN
stats s
ON ug.user = s.id
GROUP BY g.id

Insert value into subquery

I'm trying to insert the value '1' into column 'isTransfer' of every result of an subquery, but it's not working. This is the query where I select the rows:
select r.*
from players r
inner join (
select name, rating, max(id) id
from players group by name, rating
having count(distinct club) > 1
)
q on r.name = q.name and r.rating = q.rating and r.id = q.id
This is what I'm trying to do:
INSERT INTO 'isTransfer' VALUES '1' WHERE
(select r.*
from players r
inner join (
select name, rating, max(id) id
from players group by name, rating
having count(distinct club) > 1
)
q on r.name = q.name and r.rating = q.rating and r.id = q.id)
For this task, you need to do an UPDATE query. Also, you cannot use the WHERE clause like that, you will get an error. Instead, change the where clause to look where the primary key is returned by the subquery. It would look something like this:
UPDATE myTable
SET isTransfer = 1
WHERE primaryKey IN [mySubquery];
You need to make sure that the only column in your SELECT of the subquery is the primary key, otherwise you will get an invalid operand count error.
In regards to your query in the comments, the JOIN is not necessary. Instead, just get the distinct id values from the subquery like this:
SELECT DISTINCT id
FROM(
SELECT name, rating, MAX(id) AS id
FROM players
GROUP BY name, rating
HAVING COUNT(DISTINCT club) > 1) q
Then, but that query as your IN operand.
Assuming the id is unique in the players table:
update players r inner join
(select name, rating, max(id) as id
from players p
group by name, rating
having count(distinct club) > 1
) nr
on r.id = nr.id
set isTransfer = 1;

SQL Group By: Get values of 'max' record

I have a scores table:
id
user
score
date
Now, I can easily select a top 10 highscore with
SELECT user, score, date FROM scores ORDER BY score DESC
However, I'd like to include only one score per user, namely his highest. I would begin with something like
SELECT user, MAX(score) AS score FROM scores GROUP BY user ORDER BY score DESC
However, now I've lost the date that highest score was recorded. How do I get it?
You can JOIN on the table again:
SELECT s1.user, max(s1.dt), s2.mxscore as score
FROM scores s1
inner join
(
select user, max(score) mxscore
from scores
GROUP BY user
) s2
on s1.user = s2.user
and s1.score = s2.mxscore
GROUP BY s1.username, s2.mxscore
ORDER BY score DESC
See SQL Fiddle with Demo
In fact, you don't need a GROUP BY at all.
Here's the query:
SELECT scores.id, scores.user, scores.score, scores.date
FROM scores
WHERE NOT EXISTS (
SELECT *
FROM scores AS _scores
WHERE _scores.user = scores.user
AND (
_scores.score > scores.score
OR
_scores.score = scores.score AND _scores.id < scores.id)
)
and SQL Fiddle to see it working.
Note that this query properly handles the case when a user had his max score several times (it returns the record for the first max score).
You will need to relate your result with your original table:
select a.user, a.maxScore, b.maxDate
from (
select user, max(score) as maxScore
from scores group by user ) as a
inner join (
select user, score, max(date) as maxDate
from scores group by user, score) as b on a.user = b.user and a.maxScore=b.score
order by
a.maxScore desc
This query will return the maximum score for each user, and the last date when this maximum score was scored (redundant, but true)
SELECT a.*
FROM scores a
JOIN (
SELECT MAX(a.id) AS id
FROM scores a
JOIN (
SELECT user, MAX(score) AS score
FROM scores
GROUP BY user
) b ON a.user = b.user
AND a.score = b.score
GROUP BY a.user,
a.score
) b ON a.id = b.id
ORDER BY a.score DESC
This will account for cases where you have more than one of the same highest score per user. In that case, it will just take the maximum id.

Mysql - order by 2 ranks

I have a table of items. item has id, score 1, score 2.
I want to select 12 known items (using WHERE id IN (....)) and order them by a score that is the sum of score1 and score2's ranks. rank is the location of the score if the 12 items were ordered by it.
How can I do this in mysql?
Edit:
After 4 answers I see that the solution is probably more complicated than I expected. so let me ask the question in another way.
If I use select *, [calculation] from table where id IN (odered list of ids). Can I somehow use the position of each id in the original ordered list of ids in [calculation]?
Out of my head:
CREATE TEMPORARY TABLE t_1(score_1_rank INT AUTO_INCREMENT, id)
CREATE TEMPORARY TABLE t_2(score_2_rank INT AUTO_INCREMENT, id)
INSERT INTO t_1(id)
SELECT id
FROM items i
WHERE id IN ()
ORDER BY score_1
INSERT INTO t_2(id)
SELECT id
FROM items i
WHERE id IN ()
ORDER BY score_2
SELECT ...
FROM items i
INNER JOIN t_1 t1
ON t1.id = i.id
INNER JOIN t_2 t2
ON t2.id = i.id
ORDER BY t1.rank + t2.rank
Did I understand your request correctly?
Is this what you are looking to do?
SELECT
(CAST(score1 AS INT) + CAST(score2 AS INT)) AS rank
FROM items
WHERE id IN(...)
ORDER BY rank DESC
SELECT id, score1, score2,
r1.rank AS rank1,
r2.rank AS rank2,
(r1.rank + r2.rank) rankSum
FROM items i
INNER JOIN (
SELECT #rank := #rank + 1 AS rank, id
FROM items, (SELECT #rank :=0) AS r
ORDER BY score1
) AS r1 ON r1.id = i.id
INNER JOIN (
SELECT #rank := #rank + 1 AS rank, id
FROM items, (SELECT #rank :=0) AS r
ORDER BY score2
) AS r2 ON r2.id = i.id
ORDER BY rankSum
But I doubt that this will be somehow very efficient, not only because the query cannot make use of the query cache.