Question

I have a table, named city.

city_name
---------------
New York
Beijing
New York
New York
Dubai
Beijing
---------------

After update, I want it be:

city_name,   index
---------------
New York,    0
Beijing,     0
New York,    1
New York,    2
Dubai,       0
Beijing,     1
---------------

The pattern is like this: the first New York will be have an index of 0, the second New York's index is 1 and the third one will be 2. There are millions of rows in this table.

Any easy way to make this update?

I am thinking to solve this problem in two step.

First step:

@cities = Select distinct city_name from city;

Second step:

foreach @cities as @city
   update city set index = row_num where city_name = @city.cityname

It seems row_num is not availbe in mysql.

Was it helpful?

Solution

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;

OTHER TIPS

A way to do this using session() for storage AND comparing purposes:

  session_start();

  $number=0;
  $result=mysqli_query($yourconnection,"SELECT * FROM city ORDER BY city_name");

  while($row=mysqli_fetch_array($result)){

  if(empty($_SESSION["storage"])){ 
  /* THIS CONDITION ONLY GOES THROUGH THE VERY FIRST ARRAY FETCH */

  $_SESSION["storage"]=$row['city_name'];

  mysqli_query($yourconnection, "UPDATE city SET index='$number' WHERE city_name='$cityname'"); /* STORE TO THE FIRST CITY'S INDEX 0 */

  }

  else if($_SESSION["storage"]==$row['city_name']){ 
  /* IF SESSION IS THE SAME COUNTRY AS THE CURRENT ROW COUNTRY */

  $_SESSION["storage"]=$row['city_name'];

  $number=$number+1; /* INCREMENT NUMBER FOR THE SAME COUNTRY */

  mysqli_query($yourconnection, "UPDATE city SET index='$number' WHERE city_name='".$row['city_name']."'");


  }

  else {

  /* THIS IS FOR THE NEXT NEW COUNTRY */

  $number=0; /* START AGAIN THE COUNT TO 0 IF NEW COUNTRY */

  $_SESSION["storage"]=$row['city_name'];

  mysqli_query($yourconnection, "UPDATE city SET index='$number' WHERE city_name='".$row['city_name']."'");

  }

  } /* END OF WHILE LOOP */

I've done this before, but with different output but with the same logic. AND I use another table for storage purposes and comparing purposes. But the code above that I've made, I used session instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top