tags:

views:

30

answers:

1

I have table with lots of rows, and there is no id column. I'd like to go back and:

  1. add an ID column as PRIMARY KEY with AUTO_INCREMENT
  2. more importantly, retrospectively add an ID for all the existing rows, from oldest to newest (there is an 'updatetime' column).

Any suggestions?

+1  A: 

Let's consider the following example:

CREATE TABLE your_table (some_value int, updatetime datetime);

INSERT INTO your_table VALUES (100, '2010-08-11 12:09:00');
INSERT INTO your_table VALUES (300, '2010-08-11 12:08:00');
INSERT INTO your_table VALUES (200, '2010-08-11 12:07:00');
INSERT INTO your_table VALUES (400, '2010-08-11 12:06:00');
INSERT INTO your_table VALUES (600, '2010-08-11 12:05:00');
INSERT INTO your_table VALUES (500, '2010-08-11 12:04:00');
INSERT INTO your_table VALUES (800, '2010-08-11 12:03:00');

First we can add the id column:

ALTER TABLE your_table ADD id int unsigned;

Now the table looks like this:

SELECT * FROM your_table;
+------------+---------------------+------+
| some_value | updatetime          | id   |
+------------+---------------------+------+
|        100 | 2010-08-11 12:09:00 | NULL |
|        300 | 2010-08-11 12:08:00 | NULL |
|        200 | 2010-08-11 12:07:00 | NULL |
|        400 | 2010-08-11 12:06:00 | NULL |
|        600 | 2010-08-11 12:05:00 | NULL |
|        500 | 2010-08-11 12:04:00 | NULL |
|        800 | 2010-08-11 12:03:00 | NULL |
+------------+---------------------+------+
7 rows in set (0.00 sec)

Then we can UPDATE the id column with the row number when the result set is ordered by the updatetime column:

SET @row_number := 0;

UPDATE    your_table
SET       your_table.id = (@row_number := @row_number + 1)
ORDER BY  your_table.updatetime;

Now the table looks like this:

SELECT * FROM your_table ORDER BY id;
+------------+---------------------+----+
| some_value | updatetime          | id |
+------------+---------------------+----+
|        800 | 2010-08-11 12:03:00 |  1 |
|        500 | 2010-08-11 12:04:00 |  2 |
|        600 | 2010-08-11 12:05:00 |  3 |
|        400 | 2010-08-11 12:06:00 |  4 |
|        200 | 2010-08-11 12:07:00 |  5 |
|        300 | 2010-08-11 12:08:00 |  6 |
|        100 | 2010-08-11 12:09:00 |  7 |
+------------+---------------------+----+

Then we can set the id column as the primary key, and make it NOT NULL and AUTO_INCREMENT:

ALTER TABLE your_table 
MODIFY id int unsigned NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY (id);

This is the new description of the table:

DESCRIBE your_table;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| some_value | int(11)          | YES  |     | NULL    |                |
| updatetime | datetime         | YES  |     | NULL    |                |
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
+------------+------------------+------+-----+---------+----------------+
3 rows in set (0.04 sec)

We can now try to INSERT a new row in the table to confirm that AUTO_INCREMENT is working as expected:

INSERT INTO your_table (some_value, updatetime)
VALUES (900, '2010-08-11 12:10:00');

SELECT * FROM your_table ORDER BY id;
+------------+---------------------+----+
| some_value | updatetime          | id |
+------------+---------------------+----+
|        800 | 2010-08-11 12:03:00 |  1 |
|        500 | 2010-08-11 12:04:00 |  2 |
|        600 | 2010-08-11 12:05:00 |  3 |
|        400 | 2010-08-11 12:06:00 |  4 |
|        200 | 2010-08-11 12:07:00 |  5 |
|        300 | 2010-08-11 12:08:00 |  6 |
|        100 | 2010-08-11 12:09:00 |  7 |
|        900 | 2010-08-11 12:10:00 |  8 |
+------------+---------------------+----+
8 rows in set (0.00 sec)

I'm not sure if there is an easier way to tackle this, but this approach seems to do the job.

Daniel Vassallo
Thanks for the detailed instructions. I have not tried it yet but will let you know how it goes. Thanks
markelshark
Worked perfectly Daniel, THANK YOU
markelshark