MYSQL row sequence with SUM() and ORDER BY - mysql

I try to order my rows by user's total point.
SUM and ORDER BY working correctly. But also i want to add sequence numbers of rows.
When I try to use #row_number I get some numbers but sequence is incorrect.
correct num column order should be 1,2,3,4 because I use order by total_point of sum of user's points.
How can I get correct sequence for num column?
SELECT
users.user_id,
users.user_hash,
(#row_number:=#row_number + 1) AS num,
sum(total_point) as total_point
FROM (SELECT #row_number:=0) AS t,user_stats
LEFT JOIN users on users.user_id = user_stats.stats_user_id
WHERE create_date BETWEEN "2020-04-01 00:00:00" AND "2020-04-30 23:59:59"
GROUP BY stats_user_id
ORDER BY total_point DESC
v: mysql 5.7

You must use the with total sorted rows and give them a number
SELECT
user_id,
user_hash,
users.user_nick,
(#row_number:=#row_number + 1) AS num,
total_point
FROM
(SELECT
users.user_id,
users.user_hash,
users.user_nick,
SUM(total_point) AS total_point
FROM
user_stats
LEFT JOIN users ON users.user_id = user_stats.stats_user_id
WHERE
create_date BETWEEN '2020-04-01 00:00:00' AND '2020-04-30 23:59:59'
GROUP BY stats_user_id
ORDER BY total_point DESC) t1,
(SELECT #row_number:=0) AS t
ORDER BY num ASC;

Related

Get maximum value from two values

I have a table which gives the no of rides by a rider at each stand point. I need to find the stand for each rider for which he has the maximum rides.
My first result is in this format: 1
I require my final result like this: 2
I'm currently using this query, but I know it can be done in a better manner. Any suggestions would be helpful.
select c.rider_id, c.end_stand, b.max_rides
from
(select rider_id, max(rides) as max_rides
from
(select rider_id, end_stand, count(id) as rides
from ride where end_stand is not null
group by 1,2) a
group by 1
order by 2 desc, 1) b
join
(select rider_id, end_stand, count(id) as rides
from ride where end_stand is not null
group by 1,2) c
on c.rider_id = b.rider_id and c.rides = b.max_rides
order by 3 desc, 2,1
Before window functions, one method is a correlated subquery in the having clause:
select rider_id, end_stand, count(*) as rides
from ride r
where end_stand is not null
group by rider_id, end_stand
having count(*) = (select count(*)
from ride r2
where r2.end_stand is not null and
r2.rider_id = r.rider_id
group by r2.rider_id, r2.end_stand
order by count(*) desc
limit 1
);
With window functions, this is, of course, much simpler:
select *
from (select rider_id, end_stand, count(*) as rides
rank() over (partition by rider_id order by count(*) desc) as seqnum
from ride r
where end_stand is not null
group by rider_id, end_stand
) r
where seqnum = 1;
Both these will return duplicates, if there are ties for the max. The second version is easy to fix, if you want only one row: use row_number() instead of rank().

how to find index ( id ) of generic column in mysql

I have a table with name rating as this.
I am writing the query like this
SELECT user_id, sum(score) as score
FROM quiz_rashad.rating
group by user_id
order by score desc
then how I get rating index of the 12th user?
Thank you for helping.
Assuming, that "the 12th user" means the user with the ID 12:
In MySQL 8.0+ you can use dense_rank().
SELECT x.rating_index
FROM (SELECT r.user_id,
dense_rank() OVER (ORDER BY sum(r.score) DESC) rating_index
FROM quiz_rashad.rating r
GROUP BY r.user_id) x
WHERE x.user_id = 12;
Edit:
For MySQL 5.7 you have to use subqueries getting the distinct count of total scores greater than or equal the total score for the user with ID 12.
SELECT count(DISTINCT x.score) rating_index
FROM (SELECT r.user_id,
sum(r.score) score
FROM quiz_rashad.rating r
GROUP BY r.user_id) x
WHERE x.score >= (SELECT sum(r.score)
FROM quiz_rashad.rating r
WHERE r.user_id = 12)
We can try using LIMIT with OFFSET here:
SELECT user_id, SUM(score) AS score
FROM quiz_rashad.rating
GROUP BY user_id
ORDER BY score DESC
LIMIT 1 OFFSET 11;
This answer assumes that what you really want here is the record with the twelfth rank. It also assumes that no two users would be tied for the same score.

Translate Lead/Lag function to MySQL

How do I translated the below codes so that it runs in MySQL. I am new to MySQL and finding it difficult to understand few things.
CODE 1:
SELECT t1.user_id,
t1.visit_month LEAD (t1.visit_month, 1) OVER (partition BY t1.user_id ORDER BY t1.user_id, t1.visit_month)
FROM (SELECT
user_id,
month(date_time) as visit_month
FROM
tbl_activity
group by 1, 2
ORDER BY 1 , 2) t1;
Desired Output for Code 1
CODE 2:
SELECT user_id,
visit_month,
lead,
lead — visit_month AS time_diff
FROM table3
CODE 3:
SELECT user_id,
Visit_month,
lag(visit_month, 1) over (partition BY user_id ORDER BY user_id, visit_month)
FROM table
CODE 4:
SELECT user_id,
visit_month,
lag,
visit_month — lag AS time_diff
FROM table2
You could express the lead() and lag() function via subquery
select user_id, month(date_time) as visit_month,
month(date_time)-(select month(date_time) from tbl_activity
where user_id = a.user_id and
month(date_time) < month(a.date_time)
order by month(date_time) desc LIMIT 1) as time_diff -- This could be re-express via lag() function
from tbl_activity a
group by user_id, month(date_time);
In above you would need to just specify < / > to express the lead() and lag() functionality in subquery and don't forget to use order by clause
EDIT (Lead) :
select user_id, month(date_time) as visit_month,
(select month(date_time) from tbl_activity
where user_id = a.user_id and
month(date_time) > month(a.date_time)
order by month(date_time) LIMIT 1) as lead -- This could be re-express via lead() function
from tbl_activity a
group by user_id, month(date_time);

Select a custom column in MySQL

I want to display a column which calculates two custom columns.
It look something like this
SELECT to_account as account,
SUM(amount) total_claimed,
COUNT(*) as transaction_count,
((SELECT time FROM transactions WHERE to_account = account ORDER BY time DESC LIMIT 1)
- (SELECT time FROM transactions WHERE to_account = account LIMIT 1)) / 3600 as interval_hours,
(transaction_count / interval_hours) as avg_per_hour
FROM transactions
WHERE type='CLAIM' group by to_account ORDER BY COUNT(*)
I get the message "Unknown column 'thetime' in field list"
How can I work with a custom column?
You should do that using the column itself and not the alias since it's not accessible like
SELECT COUNT(*) as amount,
`time` as thetime,
(`time` / amount) as average
FROM table WHERE..
(OR) get it done in a outer query like
SELECT *, (thetime / amount) as average
FROM (
SELECT COUNT(*) as amount,
(SELECT time FROM table ...) as thetime
FROM table WHERE...)XXX;
Per your edited post, either you use the same expression again (OR) get the custom column in a outer query like
SELECT *, (transaction_count / interval_hours) as avg_per_hour
FROM (
SELECT to_account as account,
SUM(amount) total_claimed,
COUNT(*) as transaction_count,
((SELECT time FROM transactions WHERE to_account = account ORDER BY `time` DESC LIMIT 1)
- (SELECT `time` FROM transactions WHERE to_account = account LIMIT 1)) / 3600 as interval_hours
FROM transactions
WHERE type='CLAIM'
group by to_account
ORDER BY COUNT(*)
) tbl
It can be done using user defined variable,
SET #transaction_count := 0;
SET #interval_hours := 0;
SELECT to_account AS ACCOUNT,
SUM(amount) total_claimed,
#transaction_count := COUNT(*) AS transaction_count,
#interval_hours := ((SELECT TIME FROM transactions WHERE to_account = ACCOUNT ORDER BY TIME DESC LIMIT 1)
- (SELECT TIME FROM transactions WHERE to_account = ACCOUNT LIMIT 1)) / 3600 AS interval_hours,
(#transaction_count / #interval_hours) AS avg_per_hour
FROM transactions
WHERE TYPE='CLAIM' GROUP BY to_account ORDER BY COUNT(*)

How to write sql query to get items from range

I would like to get values without the smallest and the biggest ones, so without entry with 2 and 29 in column NumberOfRepeating.
My query is:
SELECT Note, COUNT(*) as 'NumberOfRepeating'
WHERE COUNT(*) <> MAX(COUNT(*))AND COUNT(*) <> MIN(COUNT(*))
FROM Note GROUP BY Note;
SELECT Note, COUNT(*) as 'NumberOfRepeating'
FROM Notes
GROUP BY Note
HAVING count(*) <
(
SELECT max(t.maxi)
FROM (select
Note, COUNT(Note) maxi FROM Notes
GROUP BY Note
) as t
)
AND
count(*) >
(
SELECT min(t.min)
FROM (select
Note, COUNT(Note) min FROM Notes
GROUP BY Note
) as t
)
try this code.
One method would use order by and limit, twice:
select t.*
from (select t.*
from t
order by NumberOfRepeating asc
limit 99999999 offset 1
) t
order by NumberOfRepeating desc
limit 99999999 offset 1;
Try this code,
Select * from Note where NumberOfRepeating < (select MAX(NumberOfRepeating) from Note ) AND NumberOfRepeating > (select MIN(NumberOfRepeating) from Note );
Here in the code, as in your table Note is the name of the table, and NumberOfRepeating is the column name, as in your table.
Try this. It should work
SELECT *
FROM ( SELECT Note, COUNT(*) as 'NumberOfRepeating'
FROM Notes
GROUP BY Note
ORDER BY NumberOfRepeating DESC
LIMIT 1, 2147483647
) T1
ORDER BY T1.NumberOfRepeating
LIMIT 1, 2147483647