Getting incorrect rank using WHERE clause in mySQL - mysql

http://sqlfiddle.com/#!9/083f5d/1
It's returning 6th rank instead of 1st rank in above SQL query. What changes I need to do in SQL query so it provides 1st rank because I have used WHERE condition to check mpkid and roundpkid (WHERE mpkid=37 AND roundpkid=3).
Here is the query:
SELECT mpkid, totalvote, rank
FROM (
SELECT mpkid, roundpkid, totalvote,
#n := IF(#g = totalvote, #n, #n + 1) rank,
#g := totalvote
FROM tr_msearch_vote_summary,
(SELECT #n := 0) i
ORDER BY totalvote DESC
) q
WHERE mpkid=37 AND roundpkid=3
What I want:
Please see sqlfiddle first. There is only one record for round #3, and it is 37 so I want that it should display rank #1 for mpkid #37 and round #3 but it is giving rank #6.

You are applying the WHERE condition after the ranking is already complete. I'm guessing you want to do the ranking after the WHERE is applied:
SELECT t.mpkid, t.roundpkid,
#n := IF(#g = t.totalvote, #n, #n + 1) rank,
#g := t.totalvote totalvote
FROM tr_msearch_vote_summary t, (SELECT #n := 0) i
WHERE t.mpkid=37 AND t.roundpkid=3
ORDER BY t.totalvote DESC
You should also initialise #g to make sure it isn't preset in another query:
SELECT t.mpkid, t.roundpkid,
#n := IF(#g = t.totalvote, #n, #n + 1) rank,
#g := t.totalvote totalvote
FROM tr_msearch_vote_summary t, (SELECT #n := 0, #g := NULL) i
WHERE t.mpkid=37 AND t.roundpkid=3
ORDER BY t.totalvote DESC
UPDATE
If you want the ranking grouped by round and then to simply SELECT by mpkid, this is a more powerful query:
SELECT mpkid,
roundpkid,
totalvote,
rank
FROM (
SELECT t.mpkid,
#n := CASE
WHEN #r = t.roundpkid AND #g = t.totalvote THEN #n
WHEN #r = t.roundpkid THEN #n + 1
ELSE 1
END rank,
#r := t.roundpkid roundpkid,
#g := t.totalvote totalvote
FROM tr_msearch_vote_summary t, (SELECT #n := 0, #g := NULL, #r := NULL) i
ORDER BY t.roundpkid, t.totalvote DESC
) r
WHERE mpkid = 37;
Note that you do not need to supply the roundpkid. See updated fiddle

Please try this query,
SELECT mpkid, totalvote, rank
FROM (
SELECT mpkid, roundpkid, totalvote,
#n := IF(#g = totalvote, #n, #n + 1) rank,
#g := totalvote
FROM tr_msearch_vote_summary,
(SELECT #n := 0) i
WHERE roundpkid=3
ORDER BY totalvote DESC
) q
WHERE mpkid=37
And here is your updated sqlfiddle. http://sqlfiddle.com/#!9/083f5d/9

Related

getting the position of a specific row mysql

I have the following code it works well, except that I cannot filter to get a specific position of a single student. I shows all students yet I just want to be able to filter and get the position of a specific child.
SELECT users.name,users.lastname, assessement_progress_reports.student_average as avg,
(#rank_count := if((#rn := (#rn + 1)) > 0,
if((assessement_progress_reports.student_average < #prev_value),
#rn,
#rank_count), NULL)
) as rank,
#prev_value := assessement_progress_reports.student_average avg
FROM assessement_progress_reports CROSS JOIN
(SELECT #prev_value := NULL, #rank_count := 1, #rn := 0) init INNER JOIN users on users.id=assessement_progress_reports.student_id where assessement_progress_reports.assessement_id=2 and assessement_progress_reports.student_stream=1 ORDER BY avg DESC

Delete duplicate data except two

How delete duplicate data except two row?
id 4 must deleted, because 'mangga' already have 3 row
This is a bit painful in MySQL. The following identifies the rows to be deleted:
select t.*
from (select t.*,
(#rn := if(#n = nama, #rn + 1,
if(#n := nama, 1, 1)
)
) as rn
from t cross join
(select #n := '', #rn := 0) params
order by nama, id
) t
where rn > 2;
You can then do the delete using a join:
delete t
from t join
(select t.*,
(#rn := if(#n = nama, #rn + 1,
if(#n := nama, 1, 1)
)
) as rn
from t cross join
(select #n := '', #rn := 0) params
order by nama, id
) tt
on t.id = tt.id
where tt.rn > 2;

How to SELECT the total row number as a column

My first query
SELECT
id,
year_,
month_
FROM
(SELECT
tp.id,
YEAR(FROM_UNIXTIME(tp.visited_date)) as year_,
MONTH(FROM_UNIXTIME(tp.visited_date)) as month_,
#rn := IF(#prev = CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)),MONTH(FROM_UNIXTIME(tp.visited_date))), #rn + 1, 1) AS rn,
#prev := CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)),MONTH(FROM_UNIXTIME(tp.visited_date)))
FROM
tr_place tp
JOIN
(SELECT #prev := NULL, #rn := 0) AS vars
ORDER BY
YEAR(FROM_UNIXTIME(tp.visited_date)) DESC,
MONTH(FROM_UNIXTIME(tp.visited_date)) DESC) AS T1
WHERE
rn < 3;
Will returns the data set This is the result which I got from the query
The subquery in it
SELECT
tp.id,
YEAR(FROM_UNIXTIME(tp.visited_date)) as year_,
MONTH(FROM_UNIXTIME(tp.visited_date)) as month_,
#rn := IF(#prev = CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)),MONTH(FROM_UNIXTIME(tp.visited_date))), #rn + 1, 1) AS rn,
#prev := CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)),MONTH(FROM_UNIXTIME(tp.visited_date)))
FROM
tr_place tp
JOIN
(SELECT #prev := NULL, #rn := 0) AS vars
ORDER BY
YEAR(FROM_UNIXTIME(tp.visited_date)) DESC,
MONTH(FROM_UNIXTIME(tp.visited_date)) DESC;
Returns data The sub query will returns this data
I need the subquery's greatest rn as a column in the first query.
How can I achieve that?
You may be having a problem with variable assignment. You should not be referencing variables in multiple expressions in the select. So, the correct way to write the first query is:
SELECT id, year_, month_
FROM (SELECT tp.id,
YEAR(FROM_UNIXTIME(tp.visited_date)) as year_,
MONTH(FROM_UNIXTIME(tp.visited_date)) as month_,
(#rn := IF (#prev = CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)), MONTH(FROM_UNIXTIME(tp.visited_date))), #rn,
if(#prev := CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)), MONTH(FROM_UNIXTIME(tp.visited_date))), 1, 1
)
) as rn
FROM tr_place tp JOIN
(SELECT #prev := NULL, #rn := 0) AS vars
ORDER BY YEAR(FROM_UNIXTIME(tp.visited_date)) DESC,
MONTH(FROM_UNIXTIME(tp.visited_date)) DESC
) t1
WHERE rn < 3;
Note the variable assignments are all in a single expression.
This may fix your issue.

Updating a column based on its position in the results

I have a query that loops through each result and updates a column:
SET #counter = 0;
UPDATE users SET rank_level = #counter := #counter + 1 ORDER BY level DESC;
SELECT rank_level, level FROM users ORDER BY rank_level ASC;
Which outputs:
But what I am trying to do is only increment the variable if the level value changes. So where the two rows that have the same level are, they would have the same rank of 8 too.
Any ideas? Thanks.
rank() is a bit tricky in MySQL. One way is with a correlated subquery:
select u.*,
(select count(*) + 1
from users u2
where u2.level < u.level
) as rank
from users u;
This is tricky to put into an update. Assuming you have a userId column, you can use join:
update users u join
(select u.*,
(select count(*) + 1
from users u2
where u2.level < u.level
) as rank
from users u
) ur
on u.userId = ur.userId
set rank_level = rank;
Doing a rank with variables is rather tricky (row_number() and dense_rank() are easier), because it requires three variables. Here is the select version:
select u.*,
(#r := if(#l = level,
if(#rn := #rn + 1, #r, #r)
if(#l := level,
#rn := #rn + 1, #rn := #rn + 1
)
)
) as ranking
from users u cross join
(select #l := -1, #rn : = 0, #r := 0) params
order by level;
So in the end I went with this:
SET #prev_value = NULL;
SET #rank_count = 0;
UPDATE users SET rank_level = CASE
WHEN #prev_value = level THEN #rank_count
WHEN #prev_value := level THEN #rank_count := #rank_count + 1
END
ORDER BY level DESC;
Based on this answer: Rank function in MySQL

Write results of SQL sub query back to database

I've been playing with this SQL code:
SELECT
id,
#prev := #curr as prev,
#curr := measure as curr,
#rank := IF(#prev > #curr, #rank+#ties, #rank) AS rank,
#ties := IF(#prev = #curr, #ties+1, 1) AS ties,
(1-#rank/#total) as percentrank
FROM
mytable,
(SELECT
#curr := null,
#prev := null,
#rank := 0,
#ties := 1,
#total := count(*) from mytable where measure is not null
) b
WHERE
measure is not null
ORDER BY
measure DESC
I'd like to write the calculated 'percentrank' back to each corresponding row of mytable in a column named "percentile," but I can't recall how to work in my update statement.
I appreciate the help.
Credit to http://code.openark.org/blog/mysql/sql-ranking-without-self-join for the SQL.
To update from a subquery, give the subquery an alias so that it's a derived table. Then use this syntax:
update YourTable
set SomeField = DerivedTable.something
, etc
from YourTable join
(subquery goes here) DerivedTable on YourTable.Whatever = DerivedTable.Whatever
etc