Given this table design in a web application:
CREATE TABLE `invoice` (
`invoice_nr` int(10) unsigned NOT NULL AUTO_INCREMENT,
`revision` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`invoice_nr`,`revision`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci
What’s the most handy and reliable way to insert a new invoice revision and get back the assigned revision number?
The first obvious approach strikes me as unreliable in a shared environment:
SELECT MAX(revision)+1 AS next_revision -- E.g. 2
FROM invoice
WHERE invoice_nr = 31416;
INSERT INTO invoice (invoice_nr, revision)
VALUES (31416, 2);
This alternative looks slightly better (I don’t know if it’s actually better):
INSERT INTO invoice (invoice_nr, revision)
SELECT 31416, MAX(revision)+1
FROM invoice
WHERE invoice_nr = 31416;
… but I can’t know the revision number unless I run a new query:
SELECT MAX(revision) AS last_revision
FROM invoice
WHERE invoice_nr = 31416;
Is there a recommended method?
App runs on PHP with good old mysql extension–mysql_query() et al.
I’ve gathered a couple of techniques from the MySQL manual. I thought I should share them here for the records.
1. Table locking
If you place a lock on the table, other simultaneous processes will be queued. Then, you don’t need any special trick to avoid dupes:
2. LAST_INSERT_ID(expr)
The LAST_INSERT_ID() function accepts an optional parameter. If set, it returns such value and it also stores it for the current session so next call to LAST_INSERT_ID() will return that value. This is a handy way to emulate sequences: