Reputation: 788
Here's the original MySQL table:
+----+-----+
| Id | Num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
When I use select Id, Num, row_number() over(partition by Num) from t
, MySQL automatically disrupts the order of the Num
column. However, I want to keep Num
column order unchanged.
Specifically, the ideal output should be like:
+----+-----+-----+
| Id | Num | row |
+----+-----+-----+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 1 | 1 |
| 6 | 2 | 1 |
| 7 | 2 | 2 |
+----+-----+-----+
How to write this MySQL query?
Upvotes: 2
Views: 2280
Reputation: 1624
Same idea as the solution proposed by Schwern. Just another style of syntax in MySQL which I find very simplistic and easy to use.
Select
id
, num
, value
from
(select
T.id,
T.num,
if( @lastnum = T.num, @Value := @Value + 1,@Value := 1) as Value,
@lastnum := T.num as num2
from
mytable T,
( select @lastnum := 0,
@Value := 1 ) SQLVars
order by
T.id) T;
DB fiddle link - https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=e04692841d091ccd54ee3435a409c67a
Upvotes: 0
Reputation: 164669
You can do this by writing your own row_number to have greater control over its partitioning.
set @prev_num = null;
set @row_number = 0;
select
id,
-- Reset row_number to 1 whenever num changes, else increment it.
@row_number := case
when @prev_num = num then
@row_number + 1
else
1
end as `row_number`,
-- Emulate lag(). This must come after the row_number.
@prev_num := num as num
from foo
order by id;
Upvotes: 1
Reputation: 222402
This is a gaps-and-islands problem. I would recommend using the difference between row numbers to identify the groups.
If id
is always incrementing without gaps:
select id, num,
row_number() over(partition by num, id - rn order by id) rn
from (
select t.*, row_number() over(partition by num order by id) rn
from mytable t
) t
order by id
Otherwise, we can generate our own incrementing id
with another row_number()
:
select id, num,
row_number() over(partition by num, rn1 - rn2 order by id) rn
from (
select t.*,
row_number() over(order by id) rn1,
row_number() over(partition by num order by id) rn2
from mytable t
) t
order by id
Demo on DB Fiddle - for your sample data, both queries yield:
id | num | rn -: | --: | -: 1 | 1 | 1 2 | 1 | 2 3 | 1 | 3 4 | 2 | 1 5 | 1 | 1 6 | 2 | 1 7 | 2 | 2
Upvotes: 3