5

I am using mysql. I have a database table with auto_increment counter set. Now because of a requirement I need to leave starting 100 ids free and move all existing records starting from 101, so current id 1 will go to 101 and id 2 will become 102 and so on.

I am able to move records to 101 but the problem is that how to change auto_increment counter to max(id)+1.

Main constraint here with me is that I need to do it in single sql statement. I can not save the value using @counter and use it later.

I tried using below query

ALTER TABLE role AUTO_INCREMENT = (SELECT rd.counter FROM (SELECT (MAX(id) + 1) AS counter FROM role r) rd);

But it is not working.

Pratz
  • 241
  • 1
  • 5
  • 13
  • 1
    "It is not working" is NOT a valid explanation of the problem you are facing. What is the **exact** error message? Did you check the documentation for [ALTER TABLE](http://dev.mysql.com/doc/refman/5.5/en/alter-table.html)? – Jocelyn May 21 '13 at 17:02
  • 1
    It is not working means it throws below error. ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT rd.counter FROM (SELECT (MAX(id) + 1) AS counter FROM role r) rd)' at line 1 – Pratz May 21 '13 at 18:35
  • 1
    And yes I checked the documentation for ALTER TABLE command but nothing is mentioned for this specific scenario. – Pratz May 21 '13 at 19:06
  • [This](http://stackoverflow.com/questions/2741485/set-auto-increment-value-programmatically) seems like the thing you need to do. It looks like you want to use an external app to perform what you want – DaveyBoy Oct 06 '14 at 15:07

4 Answers4

11

The parser does not support a subquery in the place you are trying to use it.

Here's the excerpt from the MySQL source, from sql/sql_yacc.yy:

create_table_option:
    . . .
    | AUTO_INC opt_equal ulonglong_num

What you should read there is that the AUTO_INCREMENT table option accepts only a single literal number, not an expression or a subquery or a variable or anything else. So you simply can't set the AUTO_INCREMENT in the same statement in which you do SELECT MAX(id)+1.

But you don't have to.

MySQL will never allocate an auto-increment id less than the largest value currently in the table. So if you have a table with id value 102, the next value allocated will be at least 103.

You can even try to set AUTO_INCREMENT=50 explicitly, but that will be increased automatically to MAX(id)+1.

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • Accurate answer. However, "you may have to". Auto_increment field is safe and can be prefixed with Year (etc...), then you can get autoincremented id such 2014xxxx1 2014xxxx2, etc... and require to update it once a year. – snowflake Oct 13 '14 at 11:09
  • 1
    @snowflake, I hope you don't have more than 100000 inserts to this table per year. :-) – Bill Karwin Oct 13 '14 at 15:50
  • Of course ! With unsigned big int I can go up to 18446744073709551615, which means XYYYY999999999999999 with X as leading unusable value for dates years before 1844, and YYYY as the year ! even with months and days this is a trick I like ! – snowflake Oct 13 '14 at 19:23
4

You said in your question

Main constraint here with me is that I need to do it in single sql statement. I can not save the value using @counter and use it later.

Actually you can try using dynamic SQL and see if it works as follows:

SELECT (MAX(id) + 1) INTO @counter FROM role;
SET @sql = CONCAT('ALTER TABLE role AUTO_INCREMENT=',@counter);
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

This may or may not work. Even if it does work for you, Bill Karwin's answer shows that it would not be necessary because of how MySQL already handles auto increment values. No need to manually do what MySQL already does.

Also note the first line in Bill's post

The parser does not support a subquery in the place you are trying to use it.

I wrote a crazy post explaining why in the DBA StackExchange.

Therefore, you should accept Bill's answer because the best thing to do is nothing at all.

Community
  • 1
  • 1
RolandoMySQLDBA
  • 43,883
  • 16
  • 91
  • 132
  • 1
    This may have to be the way I have to go with my similar problem; Our host did something funky that wrote data to the wrong dbs; we had to do a rollback; so I rescued critical data first, whose IDs (across a good 8 interrelated tables) would now clash with ones that have occurred since the damage was done. But the procedure written to stitch them back in with new IDs is somehow causing autoincrements are advancing n+1 records faster than the records themselves... but I can't EASILY know what the literal would be in correcting them back by one. – Joshua Eric Turcotte Feb 14 '17 at 14:33
  • @RolandoMySQLDBA Hello sir you answer is perfect But I want to the same thing for my whole table of particular Database would you please help me – Sachin Sarola Jun 27 '19 at 06:24
0

According to the maual (http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html) the auto_increment value will automatically adjust, when you insert or alter a value in the auto_increment filed manually.

So after giving your records the new id = id+100 you need not care about the auto_increment value anymore...

Peter
  • 2,051
  • 1
  • 15
  • 20
  • Aye, but in some situations (I think with certain innodb lock methods coupled with stored procedures doing multiple row inserts, etc) the autoincrement values advance more rapidly (n+1 from the looks of it) than the n number of records added, causing a divergence that wants repairs... but only being able to use a literal to do that... is complicating things. – Joshua Eric Turcotte Feb 14 '17 at 14:36
0

In response to @Peter, it appears that you will have to update the AUTO_INCREMENT value after changing changing an existing one. The following example was done on MariaDB 10.0.12:

MariaDB [test]> show create table m;
+-------+--------------------------------------------------------+
| Table | Create Table                                           |
+-------+--------------------------------------------------------+
| m     | CREATE TABLE `m` (                                     |
|       |`id` int(10) unsigned NOT NULL AUTO_INCREMENT,          |
|       |`t` varchar(10) NOT NULL DEFAULT '',                    |  
|       |PRIMARY KEY (`id`)                                      |
|       |) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+--------------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [test]> insert into m (t) values ('a'),('b');
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

MariaDB [test]> select * from m;
+----+---+
| id | t |
+----+---+
|  1 | a |
|  2 | b |
+----+---+
2 rows in set (0.00 sec)

MariaDB [test]> update m set id=id+10;
Query OK, 2 rows affected (0.05 sec)
Rows matched: 2  Changed: 2  Warnings: 0

MariaDB [test]> select * from m;
+----+---+
| id | t |
+----+---+
| 11 | a |
| 12 | b |
+----+---+
2 rows in set (0.00 sec)

MariaDB [test]> show create table m;
+-------+--------------------------------------------------------+
| Table | Create Table                                           |
+-------+--------------------------------------------------------+
| m     | CREATE TABLE `m` (                                     |
|       |`id` int(10) unsigned NOT NULL AUTO_INCREMENT,          |
|       |`t` varchar(10) NOT NULL DEFAULT '',                    |  
|       |PRIMARY KEY (`id`)                                      |
|       |) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 |
+-------+--------------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [test]> insert into m (t) values ('c');
Query OK, 1 row affected (0.04 sec)

MariaDB [test]> select * from m;
+----+---+
| id | t |
+----+---+
|  3 | c |
| 11 | a |
| 12 | b |
+----+---+
3 rows in set (0.00 sec)

MariaDB [test]>
DaveyBoy
  • 2,928
  • 2
  • 17
  • 27