开发者

Make MySQL auto-increment id (re) start from 1

"BIG" UPDATE:

Ok I was getting the whole auto-increment point wrong. I though this would be an easier way to target the first, second, third and so row, but it is just the wrong approach.

You should instead care about that the auto_increments are unique and well... that they increment. You should use the for that.

I wont delete this question because I think it might be helpful for someone else with the same wrong idea, BUT BE WARNED! :)


I have a very simple MySQL table which went like this:

id    comment    user

1     hello      name1
2     bye        name2
3     hola       name3

Then I deleted the two first comments, the result:

id    comment    user

3     hola      name3

So now when I add comments:

id    comment    user

3     hola      name3
5     chau      name4
6     xxx       name5

My problem is that I would need that whenever a row gets deleted it should "start over" and look like this.

id    comment    user

1     hola      name3
2     chau      name4
3     xxx       name5

I would like to know how is it possible to some how "restart" the table so开发者_开发百科 that it is "always" indexed 1, 2, 3 and so on.

Thanks in advance!!


I hope I have explained myself clear enough, I'm sorry for all my "plain english", feel free to edit if you think a word might be confusing :) and please ask for any clarification needed!

BTW: I did not add any of my code because this is a simplified situation and I though it be more confusing and less helpful to others, but I you think it would help (or is necessary) tell me about it!


Assuming there are no foreign key issues to deal with, this code will do it:

set @id:=0;
update mytable
set id = (@id := @id + 1)
order by id;

If there are foreign key issues, make sure your constraints are defined like this before you execute the update:

ALTER CHILD_TABLE ADD CONSTRAINT
FOREIGN KEY MYTABLE_ID REFERENCES MYTABLE
ON UPDATE CASCADE; -- This is the important bit

When it's all done, execute this to fix up the auto_increment value:

SELECT MAX(ID) + 1 FROM MYTABLE; -- note the output
ALTER TABLE MYTABLE AUTO_INCREMENT = <result from above>;


Disclaimer: I can't think of one valid reason to do this, and it can break stuff very bad. However, I'm adding this for the sake of completeness and demonstration purposes.

You could use this really ugly solution, please only do this if you're at gunpoint or your dog is held hostage!

-- Create a new veriable.
SET @newId:=0;

-- Set all id's in the table to a new one and
-- also increment the counter in the same step.
-- It's basically just setting id to ++id.
UPDATE
    yourTableHere
SET
    id=@newId:=@newId+1;

-- Now prepare and execute an ALTER TABLE statement
-- which sets the next auto-increment value.
SET @query:=CONCAT("ALTER TABLE yourTableHere AUTO_INCREMENT=", @newId+1);
PREPARE sttmnt FROM @query;            
EXECUTE sttmnt;
DEALLOCATE PREPARE sttmnt;  

This will reset all of the Ids to the position of the row in the table. Please be aware that this will reorder the rows to how MySQL gets them from the storage engine, so there's no guarantee on the order in any way.

If you have a system which is based on the Ids (like relationships between tables) then you'll be...well, let's say I hope you have a backup.


Can't be done using MySQL's autoincrement feature. You could roll your own solution, e.g. a mix between application logic and database triggers. BUT, seriosly, your design is heavily broken if it requires you to recycle UNIQUE IDs.

Couldn't you just create another table where you'd save references like that (this could be done by querying the minimum) and let your main table point to that auxilliary table?

EDIT
Here's a blog I've googled that deals with your problem: see here.


ALTER TABLE event AUTO_INCREMENT = 1;


That's not the purpose of AUTO_INCREMENT. It exists to generate unique identifiers, not to maintain a gapless sequence.

If you have a valid reason for wanting this, then generate the identifiers yourself in your code. AUTO_INCREMENT won't provide this for you.


Accentually, auto increment is made for that to increase, no matter, how much rows are there.

ALTER TABLE table AUTO_INCREMENT = 1 does reseting, but you may get some bad things, if ID's starts to repeating.

So, my advise would be - leave it alone :)


    function backup_tables($host, $user, $pass, $dbname, $tables = '*'){

    $connect = mysqli_connect($host, $user, $pass , $dbname);

     mysqli_query($connect, "SET NAMES 'utf8'");


    //get all of the tables
    if($tables == '*'){
        $tables = array();
        $result = mysqli_query($connect, 'SHOW TABLES');
        while($row = mysqli_fetch_row($result))
        {
            $tables[] = $row[0];
        }
    }
    else
    {
        $tables = is_array($tables) ? $tables : explode(',',$tables);
    }

    foreach($tables as $table){
        $table = trim($table);
    // getting all table fields
    $tblDetails = mysqli_query($connect,"SHOW FULL COLUMNS FROM $table");

    // we may need to know how to create our table
    $tblCreate = mysqli_fetch_row(mysqli_query($connect, 'SHOW CREATE TABLE '.$table));

    // getting last line from table creation script in order to get info about engine ->suffix1
    $suffix1 = end(explode(PHP_EOL,$tblCreate[1]));

        // if there is auto increment we have to remove
        if (strpos($suffix1,"AUTO_INCREMENT")){ 
            $tmpArr = explode(" ",$suffix1);
            $newStr = '';
            foreach ($tmpArr as $term){
                if (!is_int(strpos($term, "AUTO_INCREMENT"))) $newStr .= $term . ' '; else $suffix4 = $term; // suffix4 stores next value of auto_increment 
            }
            $suffix1 = $newStr;
        } // now if there is auto_increment we removed from the last line of creation table script


        $return .= "DROP TABLE IF EXISTS `".$table."` CASCADE;\n\n";

     // starting creation table with our rules
        $kgbReturn = "CREATE TABLE `$table` (\n";


        while($cols = mysqli_fetch_row($tblDetails )){

            if ($cols[2]) $cols[2] = " COLLATE " . $cols[2]; //if a charset defined add to line
            if ($cols[3]=='NO') $cols[3] = " NOT NULL"; // if the field may be null 

            $kgbReturn .= "`".$cols[0]."` ".$cols[1]. $cols[2] . $cols[3]. ",\n"; //field creation line ready
        }


        $kgbReturn = rtrim($kgbReturn,",\n") . "\n" .trim($suffix1," ") . ";\n\n"; // table creation without auto_increment


        $tblDetails = mysqli_query($connect,"SHOW FULL COLUMNS FROM $table WHERE (`Key` LIKE 'PRI%')");
        $suffix2 = '';
        while($cols = mysqli_fetch_row($tblDetails )){
            $suffix2 .= "ALTER TABLE `". $table ."` \n ADD PRIMARY KEY (`".$cols[0]."`);\n\n";
        }


        $tblDetails = mysqli_query($connect,"SHOW FULL COLUMNS FROM $table WHERE (Extra LIKE 'auto_increment%')");
        $suffix3 = '';
        while($cols = mysqli_fetch_row($tblDetails )){
            $suffix3 = "ALTER TABLE `". $table ."` \n ADD PRIMARY KEY (`".$cols[0]."`);\n\n";
            $suffix3 = "ALTER TABLE `".$table."` \n MODIFY `".$cols[0]."` ".$cols[1]." NOT NULL AUTO_INCREMENT, ".$suffix4.";";
        }






        $return .= $kgbReturn;

        $result = mysqli_query($connect, 'SELECT * FROM '.$table);
        $num_fields = mysqli_num_fields($result);

        // insert into all values 
        for ($i = 0; $i < $num_fields; $i++){

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

                $return .= 'INSERT INTO '.$table.' VALUES(';

                for($j=0; $j < $num_fields; $j++){
                    $row[$j] = addslashes($row[$j]);
                    $row[$j] = str_replace (array("\r\n", "\n", "\r", PHP_EOL), '\r', $row[$j])
    ;

                    if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return .= '""'; }
                    if ($j < ($num_fields-1)) { $return .= ','; };
                }
                $return .= ");\n";
            }
        }
        $return .= "\n\n"; // insert values completed. 


        // now add primary key and auto increment statements if exist 
        $return .= $suffix2 . $suffix3 . "\n\n\n";  


        echo "<pre>".$return ."</pre>"; // debug line. comment if you don't like.


    }


    // we need to write to a file that coded as utf-8
    $bkTime = date('Y_m_j_H_i_s');
    $fileName = 'backup-db-'.$bkTime.'.sql';
    $f=fopen($fileName,"w"); 
    # Now UTF-8 - Add byte order mark 
    fwrite($f, pack("CCC",0xef,0xbb,0xbf));

    fwrite($f,$return); 
    fclose($f); 


    }


You shouldn't really be worrying about this - the only thing an id should be is unique; its actual value should be irrelevant.

That said, here is a way (see the top comment) to do exactly what you want to do.

For those that are looking to "reset" the auto_increment, say on a list that has had a few deletions and you want to renumber everything, you can do the following.

DROP the field you are auto_incrementing.
ALTER the table to ADD the field again with the same attributes.

You will notice that all existing rows are renumbered and the next auto_increment number will be equal to the row count plus 1.

(Keep in mind that DROPping that column will remove all existing data, so if you have exterior resources that rely on that data, or the numbers that are already there, you may break the link. Also, as with any major structure change, it's a good idea to backup your table BEFORE you make the change.)


Maybe it is your approach to the solution you're trying to achieve that is not correct as what you're trying to achieve it's not possible "automatically" and doing by hand when you have thousands of rows will make your system lag.

Is it really necessary that it the system adjusts at every delete?


 update table_name set id =NULL; alter table table_name change column
 `id` `id` int auto_increment;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜