Why doesn´t it work the other way arround? SQL - mysql

so I have this command:
SELECT t.Character_ID,
#rownum := #rownum + 1 AS rank
FROM characters t,
(SELECT #rownum := 0) r
Now my table has an extra rows with the number starting from 1. Next I extend the command with a WHERE command and everything works fine:
SELECT t.Character_ID,
#rownum := #rownum + 1 AS rank
FROM characters t,
(SELECT #rownum := 0) r WHERE #rownum < 5
And now I would like to extend the command as follows:
SELECT t.Character_ID,
#rownum := #rownum + 1 AS rank
FROM characters t,
(SELECT #rownum := 0) r WHERE #rownum > 5
or
SELECT t.Character_ID,
#rownum := #rownum + 1 AS rank
FROM characters t,
(SELECT #rownum := 0) r WHERE #rownum BETWEEN 5 AND 10;
And this doesnt work and i dont know why. I doesn´t get an error or something but I got nothing as a return just an empty table. Does anyone know why?

You must use your query as a subquery and then filter:
SELECT t.*
FROM (
SELECT t.Character_ID,
#rownum := #rownum + 1 AS rank
FROM characters t, (SELECT #rownum := 0) r
) t
WHERE t.rank > 5

In the order of operations the where comes before the select - so your first query works but the other 2 don't. fix by wrapping in main query where you can test row number, search for sql order of operations for articles on this topic.

One method uses offset/limit:
SELECT t.Character_ID,
#rownum := #rownum + 1 AS rank
FROM characters t CROSS JOIN
(SELECT #rownum := 0) r
LIMIT 5 OFFSET 99999999;
Another method uses a having clause:
SELECT t.Character_ID,
#rownum := #rownum + 1 AS rank
FROM characters t CROSS JOIN
(SELECT #rownum := 0) r
HAVING rank > 5;
No subquery is needed.
Two more things. SQL tables represent unordered sets, so ORDER BY is almost always used in such a query. Second, you should also know that variables assignments in SELECT statements are deprecated. You should learn to use window functions.

Related

MySQL join table to itself based on row number returns no data

I've got a logs table with an ID column in it, and I want to do the following:
Select the ID and row number
Join the table to itself based on the row number
My objective is to get a specific row as well as the row before it. The SQL query below actually returns nothing. It's like it forgets the row number entirely. Joining on ID returns just fine.
Is there something that needs to be done in MySQL to support this kind of operation?
select * from
(select id, #rownum := #rownum + 1 as 'row'
from logs, (select #rownum := 0) r order by id) a
join
(select id, #rownum := #rownum + 1 as 'row'
from logs, (select #rownum := 0) r order by id) b
on a.row = b.row;
Change your variable name in second query, using same variable in both queries can produce unexpected results
select * from
(select id, #rownum := #rownum + 1 as 'row'
from logs, (select #rownum := 0) r order by id) a
join
(select id, #rownum1 := #rownum1 + 1 as 'row1'
from logs, (select #rownum1 := 0) r order by id) b
on a.row = b.row1;

mysql find position in recordset but grab value from another table

I have this sql that grabs the wealth ranking (position) of a single player from the players recordset. But I need to do a join to the users table to ignore banned players while finding the position.
My existing code (checking for player id 5):
SELECT z.rank FROM
(SELECT p.id, p.name, #rownum := #rownum + 1 AS rank FROM players p, (SELECT #rownum := 0) r
WHERE p.this != 'that' ORDER BY p.cash + p.bank DESC) as z #
WHERE id=5;
So what I need is something like this: (this doesn't work)
SELECT z.rank FROM
(SELECT p.id, p.name,
(SELECT ban FROM u.users WHERE id=p.account_id) as banned, #rownum := #rownum + 1 AS rank FROM players p, (SELECT #rownum := 0) r
WHERE p.this != 'that' AND banned=0 ORDER BY p.cash + p.bank DESC) as z #
WHERE id=5;
Getting too complex for me!

MySQL get rank from particular row ID

I have list of hospitals under that there are average ratings already calculated. Now I wanted to calculate rank for list of hospitals according to their average ratings from following query
SELECT name,
hospitalID,
currentAvgRating,
#curRank := #curRank + 1 AS rank
FROM hospitals h, (SELECT #curRank := 0) r
ORDER BY currentAvgRating DESC
Now above query works when I want to see all hospitals from table but when I apply WHERE clause like below then result is wrong since with this it takes row position.
SELECT name,
hospitalID,
currentAvgRating,
#curRank := #curRank + 1 AS rank
FROM hospitals h, (SELECT #curRank := 0) r where hospitalID = '453085'
ORDER BY currentAvgRating DESC
Is there any way to get correct result when we apply where clause?
If you proceed what you just found out, logically ("when there is only 1 listitem, it cannot be ordered") - you will come to the conclusion that you NEED to select ALL rows. But nothing wrong with that, you can pack them into a subselect (which isnt even an expensive one) and apply the WHERE to that:
SELECT * FROM (
SELECT name,
hospitalID,
currentAvgRating,
#curRank := #curRank + 1 AS rank
FROM hospitals h, (SELECT #curRank := 0) r
ORDER BY currentAvgRating DESC
) toplist
WHERE toplist.hospitalID = 453085
Wrap in a subquery.
SELECT * FROM (
SELECT name,
hospitalID,
currentAvgRating,
#curRank := #curRank + 1 AS rank
FROM hospitals h, (SELECT #curRank := 0) r
ORDER BY currentAvgRating DESC
)
WHERE hospitalID = '453085'

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;

Mysql selecting top 10 of each category analytic function

I have a table which has the following two columns including others: rating, price and code. Ratings is similar to a category. I wish to generate the top 10 for each rating order by price ascending where code = 'ABC'. I'm at a loss to figure out where to put the last two conditions in the following mysql statement. Please can someone advise. Many thanks
SELECT x.*
FROM (SELECT t.*,
CASE
WHEN #rating != t.rating THEN #rownum := 1
ELSE #rownum := #rownum + 1
END AS rank,
#rating := t.rating AS var_rating
FROM offers t
JOIN (SELECT #rownum := NULL, #rating := '') r
ORDER BY t.rating) x
WHERE x.rank <= 10
ALso, what if the rating column had entries like 1, 1, 1k, 1*, 1+, 2, 2, 2+, 3,3,3* etc, how would I be able to consider all of these entries as '1', 2 and 3 respectively in the same sql statement?
Try this:
SELECT x.*
FROM (SELECT t.*,
CASE
WHEN #rating != t.rating THEN #rownum := 1
ELSE #rownum := #rownum + 1
END AS rank,
#rating := t.rating AS var_rating
FROM offers t
JOIN (SELECT #rownum := NULL, #rating := '') r
WHERE code = 'ABC'
ORDER BY t.rating, price) x
WHERE x.rank <= 10
The changes are:
Added a WHERE clause after the JOIN clause
Added price to the ORDER BY clause.