Hi php users!

i have a simple question.
There are (many) ways to know the last id used in a INSERT query.

We can:

echo mysql_insert_id();

or

$query = "SELECT LAST_INSERT_id() from tablename";

but all those ways can only be used after I make a query.
i want to know which id will be used.
i can´t just get the max(id) because that one might have been deleted.

as you know mysql may (depending on table type) reuse auto increment values if records have been deleted.

do u have a solution for me?

    This is doable in Postgresql, since it uses seperate sequences, you could do:

    $res = pg_query("select nextval('seqforfield')as nextval");
    $nextval = pg_result($res,0,'nextval');
    (CODE GOES HERE)
    insert into table (field, info) values ($nextval,'$text');

    But in MySQL you have a problem with a race condition. What happens if you try to figure out the next increment without reserving it ahead of time, like pgsql's nextval does, and that script gets run twice at the exact same time? You get two scripts trying to insert the same id.

    So, the answer here may be to insert a blank record, grab the last insert id, create your data, then update that record.

      That´s exactly what i was thinking about, but i wan´t sure if that was the best and the last option.

      thanx!

        show table status LIKE 'tableName';
        or
        show table status FROM database LIKE 'tableName';

        this returns a table where one of the fields is Auto_increment and it's the next value that will be set.

          That´s a much better solution!!!!

          thanx man!

            Originally posted by delfa
            That´s a much better solution!!!!

            thanx man!

            No, that's a horrible solution, because it has a race condition, which is why I posted the way to do it is to insert a blank record, then update it. That doesn't have a race condition.

            But do it however you want. When your code blows chunks, you'll already know why.

            Unless you're going to lock the whole table while you do the show table bit through the insert. In that case it's a giant bottleneck.

              u mean if 2 processes are running the 1st might finish after the second finishes and the ID´s might get exchanged?

                Originally posted by delfa
                as you know mysql may (depending on table type) reuse auto increment values if records have been deleted.

                No, I didn't know that. Got a URL that elaborates?

                  Originally posted by delfa
                  u mean if 2 processes are running the 1st might finish after the second finishes and the ID´s might get exchanged?

                  No. I mean that two different processes may try to insert the same id twice, causing one insert to fail. There's two possible ways around this problem, one is to lock the table and increment the counter (I don't know how to do this in MySQL) and grab the new value for our own use, or to insert a dummy record, and grab it's id.

                  The problem with older but still common versions of MySQL was that they incremented their autoincrement fields by locking the table, selecting the max(id) field, inserting the new row with the max(id)+1, unlocking the row. That meant that autoincrements represented a bottleneck in performance. innodb tables, and maybe the other kinds now as well, I don't know for sure, use a seperate sequence generator that is transaction safe without locking.

                  I don't know if that counter is "visible" outside of an insert in a useful way, I'd have to look it up.

                  The nice thing about inserting an empty record, then grabbing it's id and working on that is that edit screens and entry screens become basically the same, i.e. you include a hidden field with the record number and IF there are values in the fields you show them on screen, otherwise the fields are blank. And at the same time, you're safe from entry operators trying to create the same record id twice.

                  You still have race conditions if two people are editing the same record, but that's likely to be much less common. checksumming a key field and passing that around as a needed match for updates fixes that.

                  whew. That was long.

                  Anyway, you might wanna look into innodb's autoincrement mechanisms, they're supposed to be pretty cool.

                    Originally posted by csn
                    No, I didn't know that. Got a URL that elaborates?

                    I think that's only on older versions, isn't it? (of which, said old versions are still pretty common.)

                      Originally posted by Sxooter
                      I think that's only on older versions, isn't it? (of which, said old versions are still pretty common.)

                      I've never heard of them being reused, nor experienced it. Here's all I could find at mysql.com:

                      Note that in this case (when the AUTO_INCREMENT column is part of a multiple-column index), AUTO_INCREMENT values will be reused if you delete the row with the biggest AUTO_INCREMENT value in any group. This happens even for MyISAM tables, for which AUTO_INCREMENT values normally are not reused.)

                      http://www.mysql.com/doc/en/example-AUTO_INCREMENT.html

                      When you restart the MySQL server, InnoDB may reuse an old value for an AUTO_INCREMENT column.

                      http://www.mysql.com/doc/en/InnoDB_restrictions.html

                      So if an auto increment is part of a multi-column index? Um, why for? And maybe if it's in an innodb table and mysql is restarted? How about when Mars and Venus are aligned? ;P

                        Originally posted by csn
                        I've never heard of them being reused, nor experienced it. Here's all I could find at mysql.com:

                        So if an auto increment is part of a multi-column index? Um, why for? And maybe if it's in an innodb table and mysql is restarted? How about when Mars and Venus are aligned? ;P

                        Note that first case, the using the last one, is because of the strange (by relational theory standards, and by parallel bottleneck reduction standards :-) way mysql updates autoincs (lock table, select max(id)+1, insert new row with that number, unlock table). Since Innodb does them differently, i.e. seperate sequence generators, like Postgresql or Oracle would, it apparently had a bug for a while that would let it restart with the wrong sequence number after a crash / emergency power off. I'm pretty sure that's been fixed.

                          Just curious, is there a better way mysql (with it's limitations) could get/update autoincs?

                          How does postgres handle updating sequences - use a transaction or can sequences be locked?

                            Postgresql uses sequences, and has a series of transaction safe functions for dealing with them. There's also a non-transactionally safe interface, for things like late night admin work :-)

                            The most common usage is with serial data types, which are just a macro for assigning a sequence to an integer field:

                            create table test (info text, id serial primary key);
                            NOTICE: CREATE TABLE will create implicit sequence 'test_id_seq' for SERIAL column 'test.id'
                            NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'test_pkey' for table 'test'
                            CREATE TABLE
                            \d
                            List of relations
                            Schema | Name | Type | Owner
                            --------+-------------+----------+----------
                            public | test | table | marlowe
                            public | test_id_seq | sequence | marlowe
                            (9 rows)

                            -- The following is NON transactionally safe, i.e. prone to race conditions:
                            select * from test_id_seq;
                            sequence_name | last_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called
                            ---------------+------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
                            test_id_seq | 1 | 1 | 9223372036854775807 | 1 | 1 | 1 | f | f
                            (1 row)

                            For working with the sequences, you have three functions: setval, nextval, and currval:

                            currval() only works when the current session has actually called setval or nextval, since currval only has a safe meaning after one of those has been called. Note that currval will be different for two different transactions:

                            select currval('test_id_seq');
                            ERROR: test_id_seq.currval is not yet defined in this session
                            insert into test values ('abc');
                            INSERT 109704045 1
                            select currval('test_id_seq');

                            currval

                            2
                            (1 row)

                            If I go to another window, while this one is still open:

                            insert into test values ('def');
                            INSERT 109704046 1
                            marlowe=# select currval('test_id_seq');

                            currval

                            3
                            (1 row)

                            Back to the old window:

                            select currval('test_id_seq');

                            currval

                            2
                            (1 row)

                            So each session sees the last id that was inserted by it. Note that this method allows for massive parallel operation without bottlenecks.

                              Do you know what the cache_value, log_cnt, and is_cycled columns are for?

                                Originally posted by csn
                                Do you know what the cache_value, log_cnt, and is_cycled columns are for?

                                Not really.

                                  Here we go 🙂.

                                  CSN writes:

                                  I was just wondering, what are the "cache_value",
                                  "long_cnt", and "is_cycled" sequence columns used for?

                                  cache_value: CACHE parameter from CREATE SEQUENCE
                                  is_cycled: CYCLE parameter from CREATE SEQUENCE
                                  log_cnt: internal use (number of values available without writing
                                  another WAL log entry, I think)

                                  Docs folk: is it useful to document the columns of sequence objects,
                                  or should we consider them all internal info? If they should be
                                  documented, where? I'm kind of inclined to make an entry in the "system
                                  catalogs" chapter, but I dunno what to title it ...

                                  		regards, tom lane[/QUOTE] 

                                  I forgot to look under CREATE SEQUENCE

                                    Write a Reply...