Rank values in Mysql - mysql

I am having trouble finding a solution. I need to make a column that rank from the most to the least value (column bedrag). If the values are the same then the value with the highest number ( column spelersnr ) 'wins'.
I hope you can help me out.
This is what I got so far.
SELECT s.spelersnr,
naam ,
(select max(bedrag) from boetes b where b.spelersnr = s.spelersnr) as mbedrag,
#curRank := #curRank + 1 AS POSITIE
FROM spelers s, (SELECT #curRank := 0) r
ORDER BY mbedrag ;

Given that you are using MySQL 8+, you may try using the ROW_NUMBER function here. Also, we can rewrite your query using a join, to eliminate the correlated subquery in the select clause:
SELECT s.spelersnr, s.naam,
ROW_NUMBER() OVER (ORDER BY b.mbedrag DESC, s.spelersnr DESC) rn
FROM spelers s
INNER JOIN
(
SELECT spelersnr, MAX(bedrag) AS mbedrag
FROM boetes
GROUP BY spelersnr
) b
ON s.spelersnr = b.spelersnr
ORDER BY
b.mbedrag;

Related

SQL: A column in a subquery does not appear

There is a query in MySQL 5.7:
SELECT * FROM
(
SELECT (#rowNum:=#rowNum+1) AS rowNo,t.* FROM table_target t,(SELECT (#rowNum :=0)) AS b
WHERE p_d = '2020-11-08'
ORDER BY kills DESC
) t
WHERE t.uid= '8888'
Running this query, there is no exception but column B disappears and if using select b from in the outter query, it returns unknown column exception.
I have 2 questions:
Why the (SELECT (#rowNum :=0)) does not appear?
Is the (#rowNum:=#rowNum+1) equivelent to row_number() over () in Oracle? If so, how to understand it...
Thanks for your help in advance.
In addition, I just found if I put the (SELECT (#rowNum :=0) ) in the left:
...
SELECT (SELECT (#rowNum :=0) ) AS b, (#rowNum:=#rowNum+1) AS rowNo , t.* FROM table_target t
...
Then the row number column does not increase any more, why could this happen?
You have asked 3 questions here:
Question 1: Why the (SELECT (#rowNum :=0)) does not appear?
Answer: You have used (SELECT (#rowNum :=0)) as B as a table joining it but not calling it in column list after select. That's why it is not showing it in output. You have called it as (#rowNum:=#rowNum+1) which is showing the value after increment means starting from 1.
Question 2: Is the (#rowNum:=#rowNum+1) equivalent to row_number() over () in Oracle? If so, how to understand it
Answer: Yes, it is equivalent. MySql 8.0 and above also support this (known as window function). It works as:
At the time of initialization of the query (SELECT (#rowNum :=0)) variable #rowNum will be initialized with value 0.
When we are calling (#rowNum:=#rowNum+1) in select then it will add 1 in #rowNum and assign it to itself for every row returned by select query.
This is how it will print the row number.
Question 3: if I put the (SELECT (#rowNum :=0) ) in the left:
Answer: If you put the (SELECT (#rowNum :=0) ) as field list after select then it will initialize the value of #rownum to 0 in every row returned by select. This is why you will not get incremented value.
The column "disappears" because the value is NULL. MySQL does not guarantee the order of evaluation of expressions in the SELECT, the initialization might not work.
Second, you code does not do what you intend, even if that worked, because variables may not respect the ORDER BY. I think you intend:
select k.*
from (select (#rownum := #rownumn + 1) as rownum, k.*
from (select k.*
from kills k
where k.p_d = '2020-11-08'
order by kills desc
) k cross join
(select #rownum := 0) params
) k
where t.uid = '8888';
There are probably better ways to do what you want. But your question is specifically about variables and MySQL 5.7.

Getting an auto increment variable for a join query in aws aurora mysql

I am doing a select query like this:
select #rownum := #rownum + 1 AS rank,
a.name,a.count as ad,c.count as m_count, (a.count/c.count) as ratio
from (SELECT #rownum := 0) r, Batch a, nsCount c
WHERE a.name=c.name
ORDER BY ratio DESC;
The idea is that since the results will be sorted by ratio, each row will have a column called as rank with the first row havign the highest ratio having rank 1 and so forth. But this is not how the above query is turning out to be and the first row has 2610 rank and the next row 23000 . How do I fix this?
The correct way to write this query is:
select row_number() over (order by a.count/c.count desc) as seqnum,
b.name, b.count as ad, c.count as m_count,
(a.count/c.count) as ratio
from Batch b join
nsCount c
on b.name = c.name
order by ratio desc;
Note:
The query uses meaningful table aliases.
The query uses proper, explicit, standard JOIN syntax.
row_number() is the best way to do what you want.
In order versions of MySQL, you need to use variables. This often requires a subquery for ordering:
select (#rn := #rn + 1), bc.*
from (select b.name, b.count as ad, c.count as m_count,
(a.count/c.count) as ratio
from Batch b join
nsCount c
on b.name = c.name
order by ratio desc
) bc cross join
(select #rn := 0) params

How can I update a surrogate key based on an older entry of a table

I have a table called player_stage.
I am trying to prepare my data so I can put it into a data warehouse.
I currently have a unreliable work-around that involves a duplicates view and handpicking the values from the duplicates.
I need to create a query that gives duplicates the same surrogate key(sk).
Any idea how I can do this? I've been stuck on t
his for 3 days.
If you are using MySQL 8+, then DENSE_RANK can work here:
SELECT
PLAYER_ID,
PLAYER_NAME,
DB_SOURCE,
DENSE_RANK() OVER (ORDER BY PLAYER_NAME) SK
FROM yourTable;
The above call to DENSE_RANK would assign the same SK value to all records belonging to the same player name.
If you are using a version of MySQL earlier than 8+, then we can simulate the dense rank with user variables, e.g.
SELECT t1.PLAYER_ID, t1.PLAYER_NAME, t1.DB_SOURCE, t2.rn AS SK
FROM yourTable t1
INNER JOIN
(
SELECT PLAYER_NAME, #rn := #rn + 1 AS rn
FROM (SELECT DISTINCT PLAYER_NAME FROM yourTable) t, (SELECT #rn := 0) r
ORDER BY PLAYER_NAME
) t2
ON t1.PLAYER_NAME = t2.PLAYER_NAME
ORDER BY
t1.PLAYER_ID;
Demo

sort by MySQL special group

Table A shows results that I have by running the following SQL in MySQL.
SELECT * FROM table
WHERE MATCH (title) AGAINST ('marka tv')
Table A
Table B shows results that I want to get. As you can see the groups are in round-robin order.
Table B
If I understand the question, you want to sort the output so the groups are in a round-robin fashion rather than ordered. You can do this by enumerating the values within each group and then using that information for sorting:
SELECT t.*
FROM (SELECT t.*,
(#rn := if(#g = groups, #rn + 1,
if(#g := groups, 1, 1)
)
) as rn
FROM table t CROSS JOIN
(SELECT #rn := 0, #g := '') params
WHERE MATCH (title) AGAINST ('marka tv')
ORDER BY groups
) t
ORDER BY rn, groups;
Consider a subquery in a derived table to calculate a group number to be sorted at final table:
SELECT f.*
FROM
(SELECT t1.* ,
(SELECT count(*)
FROM table t2
WHERE (t2.title <= t1.title)
AND (t1.groups = t2.groups)) AS groupNo
FROM table t1
WHERE MATCH (t1.title) AGAINST ('marka tv')
) AS f
ORDER BY groupNo, groups

Automate MySQL fields (like Excel)

Say I have a table like ID, NAME, SCORE. Now normally, to get the rankings of the teams, I'd select all and order by. Sometimes though, I don't want to know all the rankings, just the ranking of one team. If I added a column RANK, is there any way for MySQL to automatically fill in those values for me based off of SCORE? (I believe MS Excel has this capability)
and if so, how does it handle ties?
thanks
You can calculate the rankings when you make your query:
SELECT * FROM (
SELECT teams.*, #rownum := #rownum + 1 AS rank
FROM teams, (SELECT #rownum := 0) T1
ORDER BY score DESC) T2
WHERE id = 1
It works by initializing a variable called rownum to 0 and then iterating over the rows in order of decreasing score. For each team the rownum is increased and the team is assigned a rank based on the current value of rownum. The outer select applies a where clause so that only one row is returned.
Here is an improved version that assigns the same rank to teams that have tied scores:
SELECT id, name, teams.score, rank FROM (
SELECT score, #rownum := #rownum + 1 AS rank
FROM (SELECT DISTINCT(score) FROM teams) T1, (SELECT #rownum := 0) T2
ORDER BY score DESC) T3
JOIN teams ON T3.score = teams.score
If this isn't fast enough for you, then use a trigger instead.
looks like I'm looking for a MySQL trigger
Get All Teams:
SELECT
s1.name,
s1.score,
COUNT(s2.name) + 1 AS rank
FROM scores s1
LEFT OUTER JOIN scores AS s2 ON (s1.score < s2.score)
GROUP BY s1.name
ORDER BY COUNT(s2.name)
Get One Team ('The Canucks'):
SELECT
s1.name,
s1.score,
COUNT(s2.name) + 1 AS rank
FROM scores s1
LEFT OUTER JOIN scores AS s2 ON (s1.score < s2.score)
GROUP BY s1.name
HAVING s1.name = 'The Canucks'
ORDER BY COUNT(s2.name)
The method shown in the above examples get the ranking dynamically (not filling a regular or temp table).
Note: both of these assume a given team only exists once in scores table for the rank value to be correct.