get users before and after a specific user with its rank - mysql

I have a table like this:
id|name|points
1|Ralph|15
2|Dave|2
3|Mourphy|180
I need to get the user with id x and 5 users before and after him based on points rank:
I can retrive the user with
select *,rank() OVER (ORDER BY points DESC ) as rank from client where id = x;
How to retrive the others ?
Thank you

You already gave the answer inside your question.
It would be (Sql Server style)
DECLARE #myRank int
SELECT #myRank = rank() OVER (Order BY points DESC) FROM client WHERE id = x;
Select *, rank() OVER (Order BY points DESC) as rank
FROM client
HAVING rank between (#myRank - 5) and (#myRank +5);
If you want it in pure SQL, you'll have to work a little extra, but it's the same idea (just with sub-queries).

One method is to calculate the rank for "x" and to compare that to the rank for each row:
select c.*
from (select max(case when id = #x then rank end) over () as x_rank
from (select c.*, rank() OVER (ORDER BY score DESC ) as rank
from client c
) c
) c
where rank >= x_rank - 5 and rank <= x_rank + 5;
Note that this may not return exactly 11 rows if you have ties.
If you want exactly 5 before and after plus all rows with the same score:
with c as (
select max(case when id = #x then rank end) over () as x_rank
from (select c.*, rank() OVER (ORDER BY score DESC ) as rank
from client c
) c
)
(select c.*
from c
where rank < x_rank
order by rank desc
limit 5
) union all
(select c.*
from c
where rank = x_rank
) union all
(select c.*
from c
where rank > x_rank
order by rank asc
limit 5
) ;

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().

Get the rank of a user from two tables points earned and points loss

I have two MySQL tables one for points earned and one for points loss. Table structures are:
Points Earned:
id user_id points_earned date_time
And
Points Loss:
id user_id points_loss date_time
I want to get Rank of users on the basis of total_points at present, which is coming from Sum from Points Earned - Sum from points loss.
How can i get rank for all users by MySQL query.
use join and group by
select a.user_id, sum(a.points_earned )- sum(b.points_loss )
from `Points Earned` as a
left join `Points Loss` as b on a.user_id = b.user_id
group by a.user_id
If you have multiple points_earned / points_loss rows per user in the tables, you can use this query: http://sqlfiddle.com/#!9/81b33/1
SELECT
user_id,
SUM(points) AS points
FROM
(
SELECT
a.user_id,
points
FROM
(
SELECT
user_id,
SUM(points_earned) AS points
FROM
points_earned
GROUP BY
user_id
) AS a
UNION
SELECT
user_id,
SUM(points_loss) * - 1 AS points
FROM
points_loss
GROUP BY
user_id
) AS points
GROUP BY
user_id
ORDER BY
points DESC,
user_id ASC
If you want to have the actual rank as number in the result, you can use this query: http://sqlfiddle.com/#!9/81b33/3
SELECT
user_id,
points,
#curRank := IF (
#prevRank = points,
#curRank,
#incRank
) AS rank,
#incRank := #incRank + 1,
#prevRank := points
FROM
(
SELECT
*
FROM
(
SELECT
#curRank := 0,
#prevRank := NULL,
#incRank := 1
) AS count,
(
SELECT
a.user_id,
points
FROM
(
SELECT
user_id,
SUM(points_earned) AS points
FROM
points_earned
GROUP BY
user_id
) AS a
UNION
SELECT
user_id,
SUM(points_loss) * - 1 AS points
FROM
points_loss
GROUP BY
user_id
) AS points
GROUP BY
user_id
ORDER BY
points DESC,
user_id ASC
) AS ranking

MySQL: select 5 rows before and after specific row

I have table called "users" and need to select 2 rows before and after specific row, sorted by users.score ASC
users table (structure):
id name score
1 John 2
2 Sara 1
3 san 3
4 test 2
5 jery 5
6 simon 6
7 bob2 7
8 jack 4
9 man 2
for example: need to select 2 rows before and after users.id = 5 order by users.score
result should be like:
id name score
3 san 3
8 jack 4
5 jery 5
6 simon 6
7 bob2 7
thanks,
Using union all and subqueries to limit the records should do it:
select * from users where id = 5
union all (
select * from users
where score < (select score from users where id = 5)
order by score desc limit 2
)
union all (
select * from users
where score > (select score from users where id = 5)
order by score asc limit 2
)
order by score
Sample SQL Fiddle
Edit: I think a better method is to number the rows according to score and then select the rows with number -2 and +2 from the rows of id 5:
select id, name, score
from (select
t.*, #rownum1 := #rownum1 + 1 as rank
from users t, (select #rownum1 := 0) r
order by score
) a,
(select rank from (
select t.*,
#rownum := #rownum + 1 as rank
from users t, (select #rownum := 0) r
order by score
) t
where id = 5
) b
where b.rank between a.rank -2 and a.rank+2
order by score;
Sample SQL Fiddle
Perhaps using union all
(
select * from users where id < 5 order by score limit 2
)
union all
(
select * from users where id > 5 order by score limit 2
)
(SELECT x.* FROM users x JOIN users y ON y.score <= x. score WHERE y.id = 5 ORDER BY score LIMIT 3)
UNION
(SELECT x.* FROM users x JOIN users y ON y.score >= x. score WHERE y.id = 5 ORDER BY score DESc LIMIT 3)
[ORDER BY score] ;
http://www.sqlfiddle.com/#!9/45c22/42
I just write the query, based on "jpw" solution (many thanks to him)
select * from users where id = 5
union all (
select * from users
where id in (select id from users where score < (select score from users u where u.id = 5) order by score ASC)
order by score desc limit 2
)
union all (
select * from users
where id in (select id from users where score > (select score from users u where u.id = 5) order by score ASC)
order by score ASC limit 2
)
order by score
Selecting arbitrarily ordered rows before and after a specific id
SET #j = 0;
SET #i = 0;
SELECT *
FROM (
SELECT id, col1, col2, ..., #j:=#j+1 AS pos
FROM `table`
WHERE col1=... ORDER BY col1 DESC, col2 ASC
) AS zz
WHERE (
SELECT position
FROM (
SELECT id AS id2, #i:=#i+1 AS position
FROM `table`
WHERE col1=... ORDER BY col1 DESC, col2 ASC
) AS zz
WHERE id2=$currId
)
IN (pos-5,pos-4,pos-3,pos-2,pos-1,pos,pos+1,pos+2,pos+3,pos+4,pos+5)

How to get the maximum count, and ID from the table SQL

**castID**
nm0000116
nm0000116
nm0000116
nm0000116
nm0000116
nm0634240
nm0634240
nm0798899
This is my table (created as a view). Now I want to list the castID which has the most count (in this case which is nm0000116, and how many occurences/count it has in this table ( should be 5 times) and I'm not quite sure which query to use
try
Select CastId, count(*) countOfCastId
From table
Group By CastId
Having count(*)
= (Select Max(cnt)
From (Select count(*) cnt
From table
Group By CastId) z)
SELECT
MAX(E),
castId
FROM
(SELECT COUNT(castId) AS E,castId FROM [directors winning movies list] GROUP BY castId) AS t
You could just return the topmost count using LIMIT:
SELECT castID,
COUNT(*) AS Cnt
FROM atable
GROUP BY castID
ORDER BY Cnt DESC
LIMIT 1
;
However, if there can be ties, the above query would return only one row. If you want all the "winners", you could take the count from the above query as a scalar result and compare it against all the counts to return only those that match:
SELECT castID,
COUNT(*) AS Cnt
FROM atable
GROUP BY castID
HAVING COUNT(*) = (
SELECT COUNT(*)
FROM atable
GROUP BY castID
ORDER BY Cnt DESC
LIMIT 1
)
;
(Basically, same as Charles Bretana's approach, it just derives the top count differently.)
Alternatively, you could use a variable to rank all the counts and then return only those that have the ranking of 1:
SELECT castID,
Cnt
FROM (
SELECT castID,
COUNT(*) AS Cnt,
#r := IFNULL(#r, 0) + 1 AS r
FROM atable
GROUP BY castID
ORDER BY Cnt DESC
) AS s
WHERE r = 1
;
Please note that with the above method the variable must either not exist or be pre-initialised with a 0 or NULL prior to running the query. To be on the safe side, you could initialise the variable directly in your query:
SELECT s.castID,
s.Cnt
FROM (SELECT #r := 0) AS x
CROSS JOIN
(
SELECT castID,
COUNT(*) AS Cnt,
#r := #r + 1 AS r
FROM atable
GROUP BY castID
ORDER BY Cnt DESC
) AS s
WHERE s.r = 1
;

how limit start value come from other table in mysql

I have following my sql query, I want to take limit start index from the other table, How could I do it?
SELECT std.totalmarks
FROM student as std
WHERE std.status=1
ORDER BY (std.datetime) ASC
LIMIT (
SELECT us.startnum
FROM user AS us
WHERE us.username='abc'
),10
select q.totalmarks from
(
SELECT *,#curRow := #curRow + 1 AS row_number
FROM student as std JOIN (SELECT #curRow := 0) r
WHERE std.status=1
ORDER BY (std.datetime) ASC
) q
where row_number>(
SELECT us.startnum
FROM user AS us
WHERE us.username='abc'
)
limit 10
select * from
(SELECT std.totalmarks, numstart.startnum, #n:=#n+1 as number
FROM student as std,
(SELECT us.startnum
FROM user AS us
WHERE us.username='abc') as numstart,
(SELECT #n:=0) sess_var
WHERE std.status=1
ORDER BY (std.datetime) ASC) res
where number>=startnum
LIMIT 0,10