Значение приращения в новом ряду - PullRequest
0 голосов
/ 23 июня 2010

С учетом этой схемы таблицы в веб-приложении:

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

Какой самый удобный и надежный способ вставить новую редакцию счета-фактуры и вернуть назначенный номер редакции?

Первыйочевидный подход кажется мне ненадежным в общей среде:

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);

Эта альтернатива выглядит немного лучше (я не знаю, действительно ли она лучше):

INSERT INTO invoice (invoice_nr, revision)
SELECT 31416, MAX(revision)+1
FROM invoice
WHERE invoice_nr = 31416;

... но я не могу знать номер ревизии, пока не выполню новый запрос:

SELECT MAX(revision) AS last_revision
FROM invoice
WHERE invoice_nr = 31416;

Есть ли рекомендуемый метод?

Приложение работает на PHP со старым добрым mysqlрасширение - mysql_query() и др.

Ответы [ 3 ]

3 голосов
/ 23 июня 2010

Mysql имеет функцию с именем last_insert_id(), которая возвращает последний автоматически сгенерированный идентификатор. Таким образом, вы можете просто SELECT last_insert_id() сразу после ввода данных.

В PHP есть встроенная функция, которая называется mysql_insert_id().

Подробнее об этом здесь: http://www.php.net/manual/en/function.mysql-insert-id.php

Хотя это все верно и в целом полезно, на самом деле это не то, что здесь ищут. Как я это сделаю - это сгенерирую таблицы. Один называется invoice с вашим полем автоматического увеличения, а второй называется invoice_revisions. Он должен иметь тот же формат, что и таблица счетов, с добавленным полем зрения.

Затем, когда вы обновляете свою таблицу счетов-фактур, вы сначала делаете:

INSERT INTO invoice_revision SELECT i.*,IFNULL(max(ir.revision),0)+1 AS revision FROM invoice i LEFT JOIN invoice_revision ir on ir.invoice_nr = i.invoice_nr WHERE i.invoice_nr = ?

Затем обновите таблицу счетов как обычно. Таким образом, у вас есть последние данные в таблице счетов и список всех предыдущих версий в таблице invoice_revisions.

Обратите внимание, если вы используете таблицы Myisam и установите ревизию в auto_increment в этой таблице:

http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html

0 голосов
/ 28 июня 2010

Я собрал несколько приемов из руководства MySQL. Я думал, что я должен поделиться ими здесь для записей.

1. Стол запорный

Если вы установите блокировку на стол, другие одновременные процессы будут поставлены в очередь. Тогда вам не нужно никаких специальных приемов, чтобы избежать дураков:

LOCK TABLES invoice WRITE;

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);

-- Or INSERT INTO ... SELECT

UNLOCK TABLES;

2. LAST_INSERT_ID (выражение)

Функция LAST_INSERT_ID () принимает необязательный параметр. Если установлено, он возвращает такое значение и также сохраняет его для текущего сеанса, поэтому следующий вызов LAST_INSERT_ID () вернет это значение. Это удобный способ эмулировать последовательности:

CREATE TABLE `sequence` (
    `last_value` INT(50) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'Last value used'
);

START TRANSACTION;

UPDATE sequence
SET last_value=LAST_INSERT_ID(last_value+1);

INSERT INTO invoice (invoice_nr, revision)
VALUES (31416, LAST_INSERT_ID());

COMMIT;
0 голосов
/ 23 июня 2010

если вы поместите правильно изолированную транзакцию вокруг своей вставки и выберете, никто не может изменять эти таблицы между обоими операторами.

другой подход заключается в использовании хранимой процедуры для выполнения обеих команд и возврата результата.

...