Rank function in MySQL assign a rank - mysql

I need to assign a rank to TC5 not the id.
SELECT a.id, a.user_id, a.tc1, a.tc4, min(a.tc5), a.tc2, b.avatar, c.username, #curRank := #curRank + 1 AS Rank
FROM
treningove_casy a INNER JOIN
sn_users b ON a.user_id=b.id INNER JOIN
users c ON a.user_id=c.id , (SELECT #curRank := 0) r
WHERE a.tc2 LIKE 'Motokáry Modrice'
GROUP BY a.user_id
So how is the picture. Please help
The modified code
SELECT x.*, (#curRank := #curRank + 1) as Rank
FROM (SELECT a.id, a.user_id, a.tc1, a.tc4, min(a.tc5) as tc5,
a.tc2, b.avatar, c.username,
FROM sbhgl_chronoengine_chronoforms_datatable_treningove_casy a INNER JOIN
sbhgl_jsn_users b
ON a.user_id = b.id INNER JOIN
sbhgl_users c
ON a.user_id = c.id
WHERE a.tc2 LIKE 'Motokáry Modřice'
GROUP BY a.user_id
) x CROSS JOIN
(SELECT #curRank := 0) params
ORDER BY tc5 DESC;

SELECT a.id, a.user_id, a.tc1, a.tc4, a.tc2, b.avatar, c.username,
(select rank from (SELECT
IF (#score=s.tc5, #rank:=#rank, #rank:=#rank+1) rank,
#score:=s.tc5 tc5s
FROM treningove_casy s,
(SELECT #score:=0, #rank:=0) r
ORDER BY tc5 DESC) s ) as rank
FROM
treningove_casy a INNER JOIN
sn_users b ON a.user_id=b.id INNER JOIN
users c ON a.user_id=c.id , (SELECT #curRank := 0) r
WHERE a.tc2 LIKE 'Motokáry Modrice'
GROUP BY a.user_id
You can try above solution, Hope this will help you.

In MySQL, you typically use variables for ranks. In your case, you would use a subquery. I find that the variable method doesn't always work with GROUP BY:
SELECT x.*, (#curRank := #curRank + 1) as Rank
FROM (SELECT a.id, a.user_id, a.tc1, a.tc4, min(a.tc5) as tc5,
a.tc2, b.avatar, c.username,
FROM treningove_casy a INNER JOIN
sn_users b
ON a.user_id = b.id INNER JOIN
users c
ON a.user_id = c.id
WHERE a.tc2 LIKE 'Motokáry Modrice'
GROUP BY a.user_id
) x CROSS JOIN
(SELECT #curRank := 0) params
ORDER BY tc5 DESC;
Note: The use of table aliases is good. It is much easier to understand a query, though, if the aliases are abbreviations for the table names.

Related

Get ranking on mysql produce wrong ranks

i'm trying to get ranking based on rating percentage so mysql query like
select c.id , sum((r.value * 20))/ count(r1.pagetypeid) as score, #curRank := #curRank + 1 AS rank from (SELECT #curRank := 0) cr, rating as r
inner join rateelement as r1 on r.elementid = r1.id
inner join ratesubscription as r2 on r.subscriptionid = r2.id
inner join consultant as c on r2.consultantid = c.id
where r1.displayorder not in (6) and r2.agencyid = 38
group by c.id order by score desc
but it returns wrong raking indexes
what's wrong with the query?
Ranking with variables often has issues with group by -- and even order by in the most recent versions of MySQL. So, use a subquery:
select x.*, (#curRank := #curRank + 1) AS rank
from (select c.id, sum((r.value * 20))/ count(r1.pagetypeid) as score
from rating r inner join
rateelement r1
on r.elementid = r1.id inner join
ratesubscription r2
on r.subscriptionid = r2.id inner join
consultant c
on r2.consultantid = c.id
where r1.displayorder not in (6) and r2.agencyid = 38
group by c.id
order by score desc
) x cross join
(SELECT #curRank := 0) cr;

selecting only distinct row based on highest timestamp on a join

I perform a join on these two tables in mysql
Challenges table
challenge_ID(int) |to_user(int)|from_user(int)|timestamp
Users table
iduser(int)|email(string)
My join query is this :
Select distinct u.email,c.challenge_id,c.status,c.timestamp from
test.challenges c join test.users u
on
c.to_user=u.iduser
where
c.from_user=9 and (c.status='open' || c.status='rejected')
Order by
c.timestamp DESC
The result what I get from this query is
email |challenge_id| status |timestamp (Descending)
Dan21#rab.edu 5 open 2015-12-09 21:20:26
tommy52#gump.com 4 open 2015-12-09 21:10:22
Dan21#rab.edu 1 rejected 2015-12-08 12:27:00
Notice how Dan21#rab.edu is repeated twice, I want it to display only once and the one displayed should have the latest timestamp i.e.
email |challenge_id| status |timestamp (Descending)
Dan21#rab.edu 5 open 2015-12-09 21:20:26
tommy52#gump.com 4 open 2015-12-09 21:10:22
You should write your query as:
Select u.email, c.challenge_id, c.status, c.timestamp
from test.challenges c join
test.users u
on c.to_user = u.iduser
where c.from_user = 9 and c.status in ('open', 'rejected')
Order by c.timestamp DESC;
Don't use select distinct unless necessary. Then you can do what you want in various ways. Because you have a join and other conditions, I think variables might be the simplest way:
select cu.*
from (Select u.email, c.challenge_id, c.status, c.timestamp,
(#rn := if(#e = u.email, #rn + 1,
if(#e := u.email, 1, 1)
)
) as rn
from test.challenges c join
test.users u
on c.to_user = u.iduser cross join
(select #e := '', #rn := 0) params
where c.from_user = 9 and c.status in ('open', 'rejected')
order by u.email, c.timestamp DESC
) cu
where rn = 1;
EDIT:
I thought the above worked with join and the variables in a single query. But, sometimes MySQL gets confused and you need to use a subquery with variables:
select cu.*
from (select cu.*,
(#rn := if(#e = u.email, #rn + 1,
if(#e := u.email, 1, 1)
)
) as rn
from (Select u.email, c.challenge_id, c.status, c.timestamp,
from test.challenges c join
test.users u
on c.to_user = u.iduser
where c.from_user = 9 and c.status in ('open', 'rejected')
order by u.email, c.timestamp DESC
) cu cross join
(select #e := '', #rn := 0) params
) cu
where rn = 1;
I figure out a query for this which works , not sure if its foolproof or most efficient way to do this
Here it is tho
Select distinct u.email,c.challenge_id,c.status,c.timestamp
from
(select ch.challenge_id,ch.status,ch.from_user,ch.to_user,timestamp,
(select Max(timestamp) from challenges
where to_user=ch.to_user
and from_user=9
) as latest
from test.challenges ch
)c
join test.users u
on
c.to_user=u.iduser
and
c.latest=c.timestamp
where (c.status='open' || c.status='rejected')

Mysql how limit left join results

I have two tables: songs and groups
i want limit the songs are match the group to 3
i tried this:
SELECT
groups.`IDgroup`,
groups.`name` AS g_name,
songs.`IDsong`,
songs.`name` AS s_name
FROM `groups`
LEFT OUTER JOIN songs ON (groups.`IDgroup` = songs.`IDgroup` LIMIT 3)
Put the limit out of parentheses:
SELECT
groups.`IDgroup`,
groups.`name` AS g_name,
songs.`IDsong`,
songs.`name` AS s_name
FROM `groups`
LEFT OUTER JOIN songs
ON groups.`IDgroup` = songs.`IDgroup`
LIMIT 3
It is generally not a good idea to put a limit on a query that does not explicitly order its results. The reason is that it could return different results over time.
So, you may want to consider adding an
ORDER BY groups.IDgroup, songs.IDsong
to your query (before the LIMIT 3), assuming that this combination is unique.
SELECT
g.`IDgroup`,
g.`name` AS g_name,
s.`IDsong`,
s.`name` AS s_name
FROM `groups` g
LEFT OUTER JOIN songs s
using ('idgroup')
LIMIT 3
This query will return the last 3 songs for each group:
SELECT
c.`IDgroup`,
c.`name` AS g_name,
s.`IDsong`,
s.`name` AS s_name
FROM
groups c
JOIN (
SELECT
IF(#C != c.IDgroup, #ROWNUM := 1, #ROWNUM := #ROWNUM +1) AS RN,
#C := c.IDgroup,
c.IDgroup,
s.IDsong,
s.name
FROM groups c
LEFT JOIN songs s ON c.`IDgroup` = s.`IDgroup`
CROSS JOIN (SELECT #C := '') t2
ORDER BY c.IDgroup ASC
) s ON c.`IDgroup` = s.`IDgroup`
JOIN JOIN (
SELECT IDgroup, MAX(rn) AS mx
FROM (
SELECT
IF(#C != c.IDgroup, #ROWNUM := 1, #ROWNUM := #ROWNUM +1) AS rn,
#C := c.IDgroup,
c.IDgroup
FROM groups c
LEFT JOIN songs s ON c.`IDgroup` = s.`IDgroup`
CROSS JOIN (SELECT #C := '') t2
ORDER BY c.IDgroup ASC
) t
GROUP BY IDgroup
) maxsong ON maxsong.IDgroup = c.IDgroup AND s.rn BETWEEN maxsong.mx-2 AND maxsong.mx
ORDER BY c.IDgroup ASC, s.`name` ASC
Fiddle: http://sqlfiddle.com/#!2/b65c3b/1
Take the LIMIT out of the parentheses:
SELECT
groups.`IDgroup`,
groups.`name` AS g_name,
songs.`IDsong`,
songs.`name` AS s_name
FROM `groups`
LEFT OUTER JOIN songs USING (`IDgroup`)
LIMIT 3

How to use MySQL and count and rank

I'm a MS-SQL Developer, now I use this query (MySQL) ↓
SELECT A.place_idx,A.place_id,B.TODAY_CNT,C.TOTAL_CNT FROM CUSTOM_LIST
AS A
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TODAY_CNT from COUNT_TABLE where DATE(place_date) = DATE(NOW()) GROUP BY place_id)
AS B ON B.place_id=A.place_id
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TOTAL_CNT from COUNT_TABLE GROUP BY place_id)
AS C ON C.place_id=A.place_id
The result is:
I want this:
Try somethink like this:
SELECT ..., C.TOTAL_CNT, (#r := #r + 1) AS rank FROM CUSTOM_LIST, (SELECT #r := 0) t
...
ORDER BY C.TOTAL_CNT DESC
Whole query:
SELECT A.place_idx,A.place_id,B.TODAY_CNT,C.TOTAL_CNT, (#r := #r + 1) AS rank
FROM CUSTOM_LIST AS A, (SELECT #r := 0) t
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TODAY_CNT from COUNT_TABLE where DATE(place_date) = DATE(NOW()) GROUP BY place_id)
AS B ON B.place_id=A.place_id
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TOTAL_CNT from COUNT_TABLE GROUP BY place_id)
AS C ON C.place_id=A.place_id
ORDER BY C.TOTAL_CNT DESC
What if we got two same values in Total_CNT?
Maybe something like this:
SELECT ..., (#last := C.TOTAL_CNT) AS TOTAL_CNT,
IF(#last = C.TOTAL_CNT, #r, #r := #r + 1) AS rank
FROM CUSTOM_LIST, (SELECT #r := 0, #last := -1) t
...
Updated
RANK() OVER (ORDER BY TOTAL_CNT DESC DESC) AS Rank
Here I got Another Very Good Solution.:
SELECT A.place_idx,A.place_id,B.TODAY_CNT,C.TOTAL_CNT, RANK() OVER (ORDER BY TOTAL_CNT DESC) AS Rank FROM CUSTOM_LIST
AS A
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TODAY_CNT from COUNT_TABLE where DATE(place_date) = DATE(NOW()) GROUP BY place_id)
AS B ON B.place_id=A.place_id
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TOTAL_CNT from COUNT_TABLE GROUP BY place_id)
AS C ON C.place_id=A.place_id

Rank not being determined properly

I'm using this query:
SELECT A.place_idx,A.place_id,B.TOTAL_CNT,(#r := #r + 1) AS rank FROM CUSTOM_LIST
AS A
INNER JOIN
(SELECT #r := 0)
AS C
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TOTAL_CNT from COUNT_TABLE GROUP BY place_id)
AS B ON B.place_id=A.place_id order by B.TOTAL_CNT desc;
Which gives this result:
But I want this result:
How do I need to modify my query? What am I doing wrong?
SELECT *,(#r := #r + 1) AS rank FROM
(
SELECT A.place_idx,A.place_id,B.TOTAL_CNT FROM CUSTOM_LIST
AS A
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TOTAL_CNT from COUNT_TABLE GROUP BY place_id)
AS B ON B.place_id=A.place_id order by B.TOTAL_CNT desc
) AS T, (SELECT #r := 0) AS tt
Your C.rank is getting calculated as they are processed, not after they are sorted. There is really no need for this data, anyways. Since you're sorting the rows by your metric, you know the first row is the first rank, etc. You can handle it on the programming side of things after you pull it out.
Alternatively, you can put what you have in an inner select, then do the rank after.