Try this:
update city cross join
(select @city := '', @prevcity := '', @i := 0) const
set `index` = (case when (@prevcity := @city) is null then null
when (@city := city) is null then null
else @i := if(@prevcity = city, @i + 1, 1) is null then null
end)
order by city;
If you are familiar with the use of variables for enumeration in a select
statement, then this is similar. The complication is ensuring the order of evaluation for the update
. This is handled by using a case
statement, which sequentially evaluates each clause until one is true. The first two are guaranteed to be false (because the values should never be NULL
).
EDIT:
If you have a unique id, then the solution is a bit easier. I wish you could do this:
update city c
set `index` = (select count(*) from city c2 where c2.city = c.city and c2.id <= c.id);
But instead, you can do it with more joins:
update city c join
(select id, (select count(*) from city c2 where c2.city = c1.city and c2.id <= c1.id) as newind
from city c1
) ci
on c.id = ci.id
set c.`index` = ci.newind;