Yendor has asked for the wisdom of the Perl Monks concerning the following question:

Fellow Monks, I have searched high and low, brushed the dust off of my copy of "Programming the Perl DBI", and even ventured into the confines of Super Search. Unfortunately, all of my searching has been for naught, as my question remains unanswered. Either my eyes are failing me in my dotage or...Well, I certainly doubt that I'm the first person to ever want this question answered. Perhaps I'm just using the wrong search terms. I have a web site that takes customer input (name, address, email, etc.) and tosses the information into a simple database table. A simplified version of this table looks like:
CUSTOMER_INFORMATION -------------------- id (auto-incrementing sequence, not null) first_name last_name address_1 address_2 city state country postal_code ...etc...
After validating and un-tainting user input, I use the DBI to insert the information into my Postgres table like this:
$dbh = DBI->connect($dsn, $user, $pass, { RaiseError => 1, PrintError => 1, AutoCommit = +> 1 }); $sql = $dbh->prepare_cached(' INSERT INTO Customer_Information ( First_Name, Last_Name, Address_1, Address_2, City, State, Postal_Code ) VALUES ( ?, ?, ?, ?, ?, ?, ?); '); $sql->execute($FName, $LName, $Address1, $Address2, $City, $State, $PostalCode);
This code works (well, ok...The real code that I'm executing in my real script works. There might be some translation errors from script to PerlMonks in what's above.) What I'd like to know is the value of the "ID" column for the row that was just inserted. I have done this in other scripts by using what feels to me like a hack:
select max(id) from customer_information where first_name = $FName and + last_name = $LName;
Store the result of that into a variable, and voila, I have the ID I'm looking for. I need this ID to insert as a foreign key into another table immediately after this insert is run. Is there a better way to do this? Thanks kindly.

Replies are listed 'Best First'.
Re: Getting ID of last row inserted into database
by Corion (Patriarch) on Jan 25, 2006 at 18:46 UTC

    The search terms you're looking for are last insert id. And unsurprisingly, DBI has $dbh->last_insert_id ...

        yes...had some problems with that, but with this parameter combination:
        $self->db->dbh->last_insert_id(undef, undef, 'tablename', 'id_name');
        SQLite, MySQL 4.0 and PostgreSQL 8.1 all pass my tests. I think SERIAL UNIQUE NOT NULL was also necessary for Pg, but not sure.

        Aye. Reading the DBI docs that Corion pointed me to were a great help. I ended up with the following as my call to last_insert_id:

        my $LastID = $dbh->last_insert_id(undef, 'public', 'CUSTOMER_INFORMATION', 'ID');
Re: Getting ID of last row inserted into database
by saberworks (Curate) on Jan 25, 2006 at 20:21 UTC
    Also, your select of the MAX(id) is subject to a race condition - if another user does an insert between the time you insert and you fetch the id, you will get their ID (probably not what you want). The DBI functions should be associated with your statement handles, so you shouldn't have that problem.

      Right.

      That's an understood part of the problem, and also why my "select" solution felt like such a hack. I did my best to mitigate it by adding the FirstName/LastName to the WHERE clause when selecting the ID I was looking for.

      At that point, the only race condition problem would have been on someone inserting the same data multiple times during the (acknowledged) race condition period.

Re: Getting ID of last row inserted into database
by runrig (Abbot) on Jan 25, 2006 at 22:35 UTC
    Auto-incrementing fields may save you a call to the database, but I've come to appreciate sequences (where you get your unique id first, and then insert it into the database). And one (fairly) portable implementation is DBIx::Sequence.