Сложная вставка
Я использую mysql/php.
мой стол выглядит
id (int autoincrement)
voucher(varchar 25)
Я генерирую коды ваучеров, где код:
- 1 случайное число (например, 64)
- 1 фиксированный номер (например, 352)
- значение поля id (1,2,3,4,5...)
- 1 контрольная цифра (алгоритм Луна).
Очевидная проблема при работе с php заключается в том, что мне нужно сделать выбор, получить следующее значение автоинкремента, вычислить код, вставить, к этому времени могла бы быть вставлена другая строка.
То, что я хочу сделать, это вместо этого,
делать insert into vouchers (voucher) value('64352')
и пусть это создаст остальную часть меня.
Как я могу это сделать? функция / триггер?
2 ответа
Если вы используете InnoDB, проще всего будет использовать существующий код и обернуть его в транзакцию MySQL. то есть в псевдокоде:
mysql_query("START TRANSACTION");
# get next autoincrement value into: $next
# do your INSERT query
# get the actual last inserted ID into: $actual
if ($next === $actual) {
mysql_query("COMMIT");
} else {
mysql_query("ROLLBACK");
# and raise an Exception or return an error
}
EDIT / ADD:
Поскольку вы упомянули триггеры, я изучил это и считаю, что это выполнимо. Пара вопросов.
Доступ к "следующему автоинкрементному идентификатору" из триггера... Я не знаю "хорошего" способа сделать это. В запросах INSERT у вас есть доступ только к NEW, а не к OLD (существующим строкам) значениям (см. Синтаксис триггера). В этом примере я просто поддерживаю отдельный счетчик @vcount на сервере. Чтобы инициализировать это значение тем идентификатором, который вы используете в данный момент, вы просто должны сделать "SET @vcount = 42;"
Алгоритм Луна. Вы должны будете реализовать это как функцию SQL. Вот валидатор Luhn в SQL, с которого вы могли бы написать. В качестве альтернативы вы можете использовать хэш / контрольную сумму с помощью встроенной функции MySQL, такой как MD5 (и использовать только первые символы X, если вам нужен короткий код ваучера). В любом случае вам нужно сделать хеш-функцию... Я просто буду использовать "Luhn" ниже.
В любом случае вот как будет выглядеть триггер:
delimiter //
CREATE TRIGGER make_voucher_code BEFORE INSERT ON vouchers
FOR EACH ROW
BEGIN
SET @vcount = @vcount + 1;
SET NEW.voucher = CONCAT(
NEW.voucher,
CAST(@vcount AS CHAR),
Luhn(CONCAT(NEW.voucher, CAST(@vcount AS CHAR))));
END;
//
delimeter ;
Затем, в ваших INSERT, вы бы указали в запросе только "64352", как вы и предлагали. Триггер добавит остальные.
Лично, если вы или кто-то другой не сможете лучше решить проблему автоинкремента /@vcount, я все же предпочел бы выполнить транзакцию MySQL, которая лучше справится с задачей, чем хранение всего атомарного и сохранение всего кода вашего приложения на PHP.
Или выполните вставку со значением 0, затем получите идентификатор вставки, вычислите значение и обновите запись по адресу.