Ok, so this is not the typical question on how to run a query with ASC or DESC. What I need to do is the following:
I have the following table:
MySQL Order.
I need to run a query that fixes the orders. In other words, that the values for order are modified to (1-10) correctly. The result of running such query would be the following table:
MySQL correct orders
What would be the best way to achieve this?
select id, #rank := #rank + 1 as new_order
from your_table
cross join (select #rank := 0) r
order by `order`
Related
So I have a table, users, with user Balances and IDs.
With the below query, I get the table I need – which sorts the users by their balance.
SET #row_num=0; SELECT (#row_num:=#row_num+1) AS serial_num, ID, Balance FROM users ORDER BY Balance DESC; - which returns the following table:
Resulting MYSQL table
How would I find the serial_num of a specific user from the above table by ID?
I've tried SELECT * FROM ( the query above ) WHERE ID = "..."; but I must be getting something wrong with the syntax and I don't quite understand how I would implement a sub-query here.
Cheers
You had actually just 1 like mistake which lead to an uninitialized variable. Replace
SET #row_num=0;
with
SET #row_num:=0;
A little shorter version which can be run in one query would be:
SELECT *
FROM
(
SELECT ID, Balance, #row := #row + 1 AS serial_num
FROM users
CROSS JOIN (SELECT #row := 0) r
ORDER BY Balance DESC
) tmp
WHERE serial_num = 2
SQLFiddle demo
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.
I am trying to fetch first 50% of records from a MySQL Table User. I know we can use limit or top for finding them but the total number of records are not fixed so hard coding the actual number in the limit or top doesn't gives me first 50% of records. How can I achieve this?
If you are running MySQL 8.0, you can use window functions for this: ntile() does exactly what you ask for. Assuming that your ordering column is id:
select *
from (select t.*, ntile(2) over(order by id) nt from mytable) t
where nt = 1
In earlier versions, one option is a user variable and a join with an aggregate query:
select *
from (
select t.*, #rn := #rn + 1 rn
fom (select * from mytable order by id) t
cross join (select #rn := 0) x
cross join (select count(*) cnt from mytable) c
) t
where rn <= cnt / 2
Mysql directly not supports this. You can try with two queries or use subqueries
Something like this.
find the count of total records/2
that value has to be applied in the limit clause.
SET #count = (SELECT COUNT(*)/2 FROM table);
SET #sql = CONCAT('SELECT * FROM table LIMIT ', #count);
SELECT * FROM table name LIMIT (select COUNT(*)/2 from table name);
I have two tables. one is local and other one is foreign. so what I want to do is to give row numbers after joining two tables using stored procedure.
First I want to get same number of column from two tables and after that I want combine as a one table and give row numbers.
below is my query.
set #row_number=0;
select (#row_number:=#row_number + 1) as number,
(
select a.*
from
(select ID,title,last_name,first_name
from local
)
a
union all
select b.*
from
(select ID,title ,last_name,first_name
from foreign
)
b
)
;
Could anyone please tell me what the wrong with it?
Use ROW_NUMBER window function in SQL SERVER
SELECT Row_number()
OVER(
ORDER BY (SELECT NULL))AS number,a.*
FROM (SELECT ID,
title,
last_name,
first_name
FROM local
UNION ALL
SELECT ID,
title,
last_name,
first_name
FROM FOREIGN) a
Note : replace (SELECT NULL) with the column you want order by row number generation. Now the row number generation is arbitrary
It seems that you are using MySQL, not SQL Server, and try to emulate row numbers, as shown eg in this duplicate question. This is trivial to do in SQL Server using the ROW_NUMBER function, as shown by #Prdp's answer.
MySQL though doesn't have the ranking, analytic or windowing functions found in other databases. Such functions can be emulated in a very limited fashion by using non-standard SQL tricks, as shown in the linked question.
Such tricks are very limited though. A typical use of ROW_NUMBER is to rank records inside a group, eg top 10 salesmen by region. It's not possible to do that with the #curRow := #curRow + 1 trick. There are performance implications as well. This trick will only work if the rows are processed sequentially.
In the question's case, a MySQL query would probably look like this:
SELECT l.ID,
l.title,
l.last_name,
l.first_name,
#curRow := #curRow + 1 AS row_number
FROM ( select ID,title,last_name,first_name
from local
UNION ALL
select ID,title ,last_name,first_name
from foreign
) l
JOIN (SELECT #curRow := 0) r
The trick here is that JOIN (SELECT #curRow := 0) creates the variable #curRow with an initial value of 0 and returns its value. The database will take the query results and for each row, it will increase the variable and return the increased value. This can only be done at the end and forces sequential processing of the results.
By using JOIN (SELECT #curRow :=0) r you just avoid creating the variable in a separate statement.
How do I combine rows with same values in the first row and put null or space in the rows instead without affecting GROUP BY subject in the select statement? Have a look at what I am trying to achieve and help me.
My attempted query is:
SELECT regd, GROUP_CONCAT(name order by name SEPARATOR ' ') as name,
subject, sc, fm FROM table GROUP BY regd, subject
Firstly, I would suggest that you handle this in code rather than at the DB level!
But, if you absolutely must do it all in a query, you could try ranking over partition with the regd column being the partition. Your expected output has rather arbitrarily ordered rows within each regd.
This query will order by subject within each regd:
select t.regd,
case when r=1 then t.name else null end as name,
t.subject,
t.sc,t.fm
from
(
select tt.*,
case when regd = #curRegd then #rank := #rank +1 else #rank:=1 end as r,
#curRegd := tt.regd
from table tt
join (SELECT #curRegd := 0,#rank:=0) r
order by regd,subject
) t
Finally, based on your stored data example, it seems like no aggregation i.e. GROUP BY clause, is necessary here.