MySql Ranking users - mysql

I am using this code to rank users:
SELECT #rn:=#rn+1 AS rank, userid, amount
FROM (
SELECT userid, sum(amount) AS amount
FROM leads WHERE date(time)='2013-09-15'
GROUP BY userid
ORDER BY amount DESC
) t1 , (SELECT #rn:=0) t2;
The result is like this:
rank userid amount
1 11 1.15
2 10 1.15
It keeps adding rank even if the user has the same amount, any ideas how to fix this? Yes, I have searched google and here on stackoverflow, but I have not been able to fix this problem.

First, you don't need a subquery to do what you want.
The following does a dense ranking of the amounts, by introducing another variable to remember the total amount:
SELECT userid, sum(amount) AS amount,
if(#amount = amount, #rn, #rn := #rn + 1) as ranking,
#amount := amount
FROM leads cross join
(select #rn := 0, #amount := -1) const
WHERE date(time) = '2013-09-15'
GROUP BY userid
ORDER BY amount DESC;

Related

What would the equivalent statement be in MySQL 5.6.39?

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'

Rank each employee based on their merit points from highest to lowest

Create two tables emp_merits (meritid, empid, date, meritpoints),emp1(empid,empname) Each employee will be given merit points every month based on their performance. So same employee can have multiple entries in the table with different meritpoints.
List all the merits received by a specific employee (empid will be input here) between specific dates
Rank each employee based on their merit points from highest to lowest
so far i have tried this query
select empid , sum (meritpoints) as totalmerits , (DENSE_RANK()OVER (PARTITION BY empid ORDER BY meritpoints desc)) AS rank from emp_merit
group by empid,meritpoints
order by empid ,totalmerits desc
You could try this:
SELECT #rownum := #rownum + 1 AS rank, a.*
FROM (
SELECT empid, sum(meritpoints) AS totalmerits
FROM emp_merits
GROUP BY empid
ORDER BY totalmerits) a, (SELECT #rownum := 0) r ;
you probably need your specific dates in the WHERE-clause.
You can implement dense_rank() using variables:
select empid, totalmerits,
(#rn := if(#m = totalmerits, #rn,
if(#m := totalmerits, #rn + 1, #rn + 1)
)
) as rank
from (select empid, sum(meritpoints) as totalmerits
from emp_merit
group by empid
order by totalmerits desc
) e cross join
(select #m := -1, #rn := 0) params;

Fetch last three orders from a table

Consider a table with the following columns:
Customer Email ID
Payment Method (COD/ Netbanking/ CreditCard/ DebitCard)
Order ID
Order Creation Date
Order Status(Success/ Failed/ Cancelled)
How do I fetch the last three successful orders past 3 months for each customer from these table in SQL along with the relevant details?
This is a bit painful in MySQL. Probably the simplest method is to use variables.
Your column names are not clear. And you have some additional conditions, but this is the basic idea:
select t.*
from (select t.*,
(#rn := if(#c = customerid, #rn + 1,
if(#c := customerid, 1, 1)
)
) as rn
from t cross join
(select #rn := 0, #c := '') params
order by customerid, orderdate desc
) t
where rn <= 3;
You can add the additional where conditions to the subquery.
I Hope this helps
SELECT *
FROM TABLENAME
WHERE OrderStatus='Success'
ORDER BY OrderCreationDate DESC
LIMIT 3;

I need to find any 5 rows that match where clause and they occur "in a row" (they are neighbors)

I have a MySQL table for fictional fitness app.
Let's say that app is monitoring user progress on doing pushups day by day.
TrainingDays
id | id_user | date | number_of_pushups
Now, I need to find if user have ever managed to do more than 100 pushups 5 days in a row.
I know this is probably doable by fetching all days and then making some php loops, but I wonder if there is possibility to do this in plain mysql...
In MySQL, the easiest way is to use variables. The following gets all sequences of days with 100 or more pushups:
select grp, count(*) as numdaysinarow
from (select (date - interval rn day) as grp, td.*
from (select td.*,
(#rn := if(#i = id_user, #rn + 1
if(#i := id_user, 1, 1)
) as rn
from trainingdays td cross join
(select #rn := 0, #i := NULL) vars
where number_of_pushups >= 100
order by id_user, date
) td
) td
group by grp;
This uses the observation that when you subtract a sequence of numbers from a series of dates that increment, then the resulting value is constant.
To determine if there are 5 or more days in a row, use max():
select max(numdaysinarow)
from (select grp, count(*) as numdaysinarow
from (select (date - interval rn day) as grp, td.*
from (select td.*,
(#rn := if(#i = id_user, #rn + 1
if(#i := id_user, 1, 1)
) as rn
from trainingdays td cross join
(select #rn := 0, #i := NULL) vars
where number_of_pushups >= 100
order by id_user, date
) td
) td
group by grp
) td;
Your app can then check the value against whatever minimum you like.
Note: this assumes that there is only one record per day. The above can easily be modified if you are looking for the sum of the number of pushups on each day.
Order of records shouldn't be relied on, e.g. with ORDER BY you can change the sequence.
However, you have many functions at hand in a database, which also enables you to use less PHP. What you want is SUM function. Combined with a WHERE clause, this should get you started:
SELECT SUM(number_of_pushups) AS sum_pushups
FROM TrainingDays
WHERE date >= :start_day
AND user_id = :user_id

Mysql Adding values in a column based on values in other column

What is the mysql query to get the below result from the table?. Addition in the amount column should be carried out based on the invoiceID.
SELECT #rownum := #rownum + 1 AS ID, InvoiceID, SUM(AMOUNT)
FROM <tablename>, (SELECT #rownum := 0) r
GROUP BY InvoiceID
select ID,InvoiceID, SUM(Amount)
from <table>
group by InvoiceID
try this:
select #i:=#i+1 AS id,a.*
from
(select InvoiceID,sum(Amount) as Amount
from your_table
group by InvoiceID)a,(SELECT #i:=0) r
SQL Fiddel demo