What would the equivalent statement be in MySQL 5.6.39? - mysql

I recently moved to a shared host that has MySQL 5.6.39 instead of MariaDB 10.x, I was wondering what would the equivalent of the following MariaDB statement in MySQL?
SELECT rank,
total
FROM
(SELECT ROW_NUMBER() OVER (
ORDER BY `prestige` DESC, `xp` DESC) AS rank,
(SELECT COUNT(*)
FROM Modular_LS) AS total,
steamid
FROM Modular_LS) sub
WHERE sub.steamid = '%s'
I got as far as this, but now I'm stuck
SELECT rank, total FROM
(SELECT #rank := #rank +1 as rank FROM Modular_LS,
(SELECT COUNT(*) FROM Modular_LS) AS total, steamid FROM Modular_LS) sub,
(SELECT #rank := 0) r ORDER BY `prestige` DESC, `xp` DESC) t;
The table structure contains the column steamid, xp, prestige
My goal is to order by prestige descending first and then xp descending to put it in a ranking like-order, then using WHERE query to find a specific player's ranking. The output of which contains the rank (position) and the total (total amount of records)

Maybe this will get you started:
SELECT #rank := IF(player_id = #prev, #rank + 1, 1), #prev := player_id
FROM ( SELECT #rank := 1, #prev = 0 ) AS init
JOIN ( SELECT player_id
FROM Modular_LS
ORDER BY prestige DESC, SP DESC
) AS x ;

After a few hours, this is what I came up with that solved my problem.
SELECT
sub.rank
,sub.total
FROM
(
SELECT
t.id
,t.steamid
,#rownum : = #rownum + 1 AS rank
,(
SELECT
COUNT (*)
FROM
Modular_LS
) AS total
FROM
Modular_LS t JOIN (
SELECT
#rownum : = 0
) r
ORDER BY
t.prestige DESC
,t.xp DESC
) sub
WHERE
sub.steamid = '%s'

Related

MySQL: Select last x items of each user

I have a table with lots of timestamped entries for each user in my system:
id (int, PK)
user_id (int, FK)
date (datetime)
description (text)
other columns...
How do I select the last x (e.g. 2) items of each user?
(By last items, I mean of course items sorted desc by date)
Have a correlated sub-query to find a user_id's "second last" date:
select t1.*
from tablename t1
where t1.date >= (select date from tablename t2
where t2.user_id = t1.user_id
order by date desc
limit 1,1)
If you want 3 last rows for each user, adjust to LIMIT 2,1.
Try this:
SELECT t.id, t.user_id, t.`date`, t.`description`
FROM (SELECT id, user_id, `date`, `description`
FROM mytable t1
ORDER BY t1.date desc
LIMIT X) t --Change x to the number which you want.
GROUP BY t.id, t.user_id, t.`date`, t.`description`
Give a row number based on user_id order by descending order of date. Then select the rows having row number 1 and 2.
Query
select t1.id, t1.user_id, t1.`date`, t1.`description` from
(
select id, user_id, `date`, `description`,
(
case user_id when #curA
then #curRow := #curRow + 1
else #curRow := 1 and #curA := user_id end
) as rn
from ypur_table_name t,
(select #curRow := 0, #curA := '') r
order by user_id, `date` desc
)t1
where t1.rn in (1, 2); -- or change t1.rn <= 2. Change 2 accordingly
You can use below query-
SELECT x.*
FROM (SELECT t.*,
CASE
WHEN #category != t.user_id THEN #rownum := 1
ELSE #rownum := #rownum + 1
END AS rank,
#category := t.user_id AS var_category
FROM your_table AS t
JOIN (SELECT #rownum := NULL, #category := '') r
ORDER BY t.user_id,t.date DESC,t.id) x
WHERE x.rank<=2;
Note: x.rank<=2, put here how many rows you need user wise.

MariaDB/MySQL RANK() implementation

I am working on migration from MS SQL Server to MariaDB 10.0. I have query which use RANK() PARTITION BY. I already created some kind of RANK() implementation on my table but it's not working properly.
The original query was:
RANK() OVER (PARTITION BY visits.id_partner ORDER BY visits.updated_at DESC) AS rank
My implementation for MariaDB/MySQL:
SELECT
...,
(
CASE visits.id_partner
WHEN #currId THEN
#curRow := #curRow + 1
ELSE
#curRow := 1 AND #currId := visits.id_partner
END
) AS rank
FROM
records rec
JOIN visits ON visits.id = rec.id_visit,
(
SELECT
#curRank := 0,
#currId := NULL
) r
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC
I want to select row ranked by id_partner order by updated_at field. When id_partner is same as on row before RANK should increase by 1. When is different than before, it should reset to 1.
But my query is not working at all. I have still rank 1 on all rows. Can you help me find mistake?
Thank you for help!
It is tricky to use variables in MySQL/MariaDB. A variable should only be used and assigned in one statement (as you do correctly). However, AND can short-circuit variable assignment.
I use a construct like this for ROW_NUMBER(). RANK() is actually a bit of a pain . . . DENSE_RANK() and ROW_NUMBER() are simpler. However, this seems to be the code that you are aiming for:
SELECT ...,
(#rn := if(#currId = visits.id_partner, #rn + 1,
if(#currId := visits.id_partner, 1, 1)
)
) as rank
FROM records rec JOIN
visits
ON visits.id = rec.id_visit CROSS JOIN
(SELECT #rn := 0, #currId := NULL) params
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC;
EDIT:
In MySQL (and presumably in MariaDB), sometimes variables don't work quite right unless you use a subquery. So, try this:
SELECT . . .,
(#rn := if(#currId = visits.id_partner, #rn + 1,
if(#currId := visits.id_partner, 1, 1)
)
) as rank
FROM (SELECT ...
FROM records rec JOIN
visits
ON visits.id = rec.id_visit
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC
) t CROSS JOIN
(SELECT #rn := 0, #currId := NULL) params;

To display top 4 rows using mysql Rank is displaying wrong

I need to display the top4 and lease 4 rows based Amount and group by agentId but here rank is showing wrong
And how to show least(last 4 rows?)
schema:
AgentID amount
1 3000
1 3200
2 9000
SELECT Agentid,SUM(AmountRecevied) as Amount,#rownum := #rownum + 1 AS Rank
FROM collection ,(SELECT #rownum := 0) r
GROUP BY AgentID
ORDER BY Amount DESC
limit 4;
Try this way:
SELECT T.Agentid,T.Amount, #rownum := #rownum - 1 AS Rank
FROM
(SELECT Agentid,SUM(AmountRecevied) as Amount
FROM collection
GROUP BY AgentID
ORDER BY Amount
LIMIT 4) T,(SELECT #rownum := 11) r
Try this :
SELECT
C.*,
#rownum := #rownum + 1 AS Rank
FROM (
SELECT
Agentid,
SUM(AmountRecevied) as Amount
FROM collection
GROUP BY AgentID
ORDER BY Amount DESC
LIMIT 4
) AS C, (SELECT #rownum := 0) r
In case of amount matching for different agentids, then, I believe, ranks should be assigned same.
This solution should help you:
select
/*case when rank>6 then '' else rank end as */
rank, agentid, amount
from (
select agentid, #ca:=amount amount
, case when #pa=#ca then #rn:=#rn
else #rn:=( #rn + 1 )
end as rank
, #pa:=#ca as temp_currAmount
from ( select agentid, sum(amount) as amount
from agents
group by agentid
order by amount
) amounts_summary,
(select #pa:=0, #c0:=0,
#rn:=0) row_nums
order by rank desc
) results
where rank > 6
order by rank
;
Demo # MySQL 5.6.6 Fiddle
And if you want no display ranks greater than '6' but empty, then
just uncomment the case line and comment the where condition line
select
case when rank>6 then '' else rank end as
rank, agentid, amount
from (
select agentid, #ca:=amount amount
, case when #pa=#ca then #rn:=#rn
else #rn:=( #rn + 1 )
end as rank
, #pa:=#ca as temp_currAmount
from ( select agentid, sum(amount) as amount
from agents
group by agentid
order by amount
) amounts_summary,
(select #pa:=0, #ca:=0,
#rn:=0) row_nums
order by rank
) results
-- where rank > 6
order by rank
;
You can modify asc or desc as required.
Demo # MySQL 5.6.6 Fiddle

MySQL Ranking ID with Ties Based on Column Returns Error

I have a 1 table database with (in a simplified form) the following fields:
user_id(INT), ref_id(INT), points(INT), pointsgiven(BOOL/TINY_INT)
I want a query that returns the RANK of the user_id I specify based on points, given that pointsgiven is true. The kicker is, I need ties included. I can get a result set for ALL ranks if I want with the following query
SELECT
user_id, ref_id, points, pointsgiven,
CASE
WHEN #points = COALESCE(points, 0) THEN #rownum
ELSE #rownum := #rownum + 1
END AS rank,
#points := COALESCE(points, 0)
FROM users CT
JOIN
(
SELECT #rownum := 0, #points := NULL
) r
WHERE pointsgiven=TRUE ORDER BY points DESC
So, based on that, I thought I could just use that as a subquery to get a certain user_id as follows:
select * from
(
SELECT
user_id, ref_id, points, pointsgiven,
CASE
WHEN #points = COALESCE(points, 0) THEN #rownum
ELSE #rownum := #rownum + 1
END AS rank,
#points := COALESCE(points, 0)
FROM users CT
JOIN
(
SELECT #rownum := 0, #points := NULL
) r
WHERE pointsgiven=TRUE ORDER BY points DESC
) as derived WHERE user_id = 15
But this returns [BLOB - 1 B] as the rank on the correct user_id. What am I doing wrong here?
I have no idea why your query isn't working. For a single user id, though, you can use a correlated subquery:
select user_id, ref_id, points, pointsgiven,
coalesce((select count(distinct user_id)
from users u2
where u2.pointsgiven=TRUE and
u2.points > u.points
) + 1, 1) as rank
from users u
where user_id = 15;
An index on users(pointsgiven, points, user_id) should be used by the query.
To look at just one ranking, this might even be faster than your method.

COUNT() with nulls, inside subquery

I have a bit of a problem with an advanced query that I am struggling to get my head around.
Essentally there are votes in a votes table that correspond to a given soundtrack. My query needs to get a rank for a soundtrack based on the votes that it has been awarded.
My approach below works just fine when there are votes in the table but the rank is given a NULL value when there are none in there.
Here's the query:
SELECT soundtrack.*,
(SELECT WrappedQuery.rank
FROM (SELECT #rownum := #rownum + 1 AS rank,
prequery.soundtrack_id
FROM (SELECT #rownum := 0) sqlvars,
(SELECT Count(*),
soundtrack_id
FROM vote
GROUP BY vote.soundtrack_id
ORDER BY Count(*) DESC) prequery) WrappedQuery
WHERE WrappedQuery.soundtrack_id = soundtrack.id) AS rank
FROM soundtrack
WHERE soundtrack.id = 33
AND live = 1
ORDER BY rank ASC
I have a feeling the problem is to do with the (SELECT COUNT(*)) part, but everything I have tried so far isn't working out.
Hoping someone could shed some light on my issue.
EDIT
Here's the SQLFiddle
http://www.sqlfiddle.com/#!2/c8db2/2/0
THAT ONE IS GOOD:
SELECT soundtrack.*,
(SELECT WrappedQuery.rank
FROM (SELECT #rownum := #rownum + 1 AS rank,
prequery.soundtrack_id
FROM (SELECT #rownum := 0) sqlvars,
(
SELECT COALESCE(COUNT(vote.soundtrack_id),0) AS no_rows,
soundtrack.id AS soundtrack_id
FROM soundtrack
LEFT JOIN vote ON soundtrack.id=vote.soundtrack_id
GROUP BY soundtrack.id
ORDER BY 1 DESC
) prequery) WrappedQuery
WHERE WrappedQuery.soundtrack_id = soundtrack.id) AS rank
FROM soundtrack
ORDER BY rank ASC;
SEE: http://www.sqlfiddle.com/#!2/74698/2/0
I've had some luck ranking in my own work using the row_number function. But otherwise, the coalesce function might help you out.
SELECT soundtrack.*, rankquery.rank
FROM (
SELECT row_number() over(partition by prequery.soundtrack_id order by prequery.num_votes) as rank,
prequery.soundtrack_id
FROM (
SELECT COALESCE(COUNT(*),0) as num_votes, soundtrack_id
FROM vote
GROUP BY soundtrack_id
ORDER BY num_votes DESC
) prequery
) rankquery
INNER JOIN soundtrack
rankquery.soundtrack_id = soundtrack.id
WHERE soundtrack.id = 33
AND live = 1
ORDER BY rank
SELECT soundtrack.*, rankquery.rank
FROM(
SELECT prequery.*, #rownum := #rownum + 1 AS rank
(
SELECT COALESCE(Count(*),0) as num_votes,
soundtrack_id
FROM vote
GROUP BY soundtrack_id
ORDER BY num_votes DESC
) as prequery,
(SELECT #rownum := 0) as sqlvars
) rankquery
INNER JOIN soundtrack
rankquery.soundtrack_id = soundtrack.id
WHERE soundtrack.id = 33
AND soundtrack.live = 1
ORDER BY rankquery.rank ASC