Как вставить много строк в таблицу MySQL и вернуть новые идентификаторы?
Обычно я могу вставить строку в таблицу MySQL и вернуть last_insert_id
назад. Теперь, однако, я хочу, чтобы массив вставлял много строк в таблицу и возвращал массив идентификаторов. Кто-нибудь знает, как я могу это сделать?
Есть несколько подобных вопросов, но они не совсем то же самое. Я не хочу вставлять новый ID во временную таблицу; Я просто хочу вернуть массив идентификаторов.
Можно ли получить lastInsertId из объемной вставки?
Mysql mulitple row insert-select statement with last_insert_id()
Ответы
Ответ 1
Старый поток, но только что рассмотрел это, поэтому здесь: если вы используете InnoDB в последней версии MySQL, вы можете получить список идентификаторов, используя LAST_INSERT_ID()
и ROW_COUNT()
.
InnoDB гарантирует последовательные числа для AUTO INCREMENT при выполнении массовых вставок, при условии, что innodb_autoinc_lock_mode
установлен в 0 (традиционный) или 1 (последовательный).
Следовательно, вы можете получить первый идентификатор из LAST_INSERT_ID()
и последний, добавив ROW_COUNT()-1
.
Ответ 2
Единственный способ, я могу думать, что это можно сделать, - это сохранить уникальный идентификатор для каждого набора вставленных строк (guid)
затем выберите идентификаторы строк.
например:
INSERT INTO t1
(SELECT col1,col2,col3,'3aee88e2-a981-1027-a396-84f02afe7c70' FROM a_very_large_table);
COMMIT;
SELECT id FROM t1
WHERE guid='3aee88e2-a981-1027-a396-84f02afe7c70';
Вы также можете генерировать guid в базе данных с помощью uuid()
Ответ 3
Предположим, что у нас есть таблица под названием temptable с двумя cols uid, col1, где uid - это поле автоматического приращения. Выполнение чего-то вроде ниже вернет весь вставленный идентификатор в наборе результатов. Вы можете просмотреть результаты и получить свой идентификатор. Я понимаю, что это старый пост, и это решение может не работать для каждого случая. Но для других это может и почему я отвечаю на это.
# lock the table
lock tables temptable write;
#bulk insert the rows;
insert into temptable(col1) values(1),(2),(3),(4);
#get the value of first inserted row. when bulk inserting last_insert_id() #should give the value of first inserted row from bulk op.
set @first_id = last_insert_id();
#now select the auto increment field whose value is greater than equal to #the first row. Remember since you have write lock on that table other #sessions can't write to it. This resultset should have all the inserted #id's
select uid from temptable where uid >[email protected]_id;
#now that you are done don't forget to unlock the table.
unlock tables;
Ответ 4
Я думаю, вам придется либо обрабатывать идентификатор транзакции в вашем приложении, либо идентификатор элемента в вашем приложении, чтобы сделать это безупречно.
Один из способов сделать это, который может работать, считая, что все ваши вставки успешно (!), выглядит следующим образом:
Затем вы можете получить вставленный идентификатор с циклом для числа затронутых строк, начиная с lastid (который является первым вставленным идентификатором объемной вставки).
И, таким образом, я проверил, что он отлично работает. Просто будьте осторожны, что HeidiSQL, например, не вернет правильное значение для ROW_COUNT(), возможно, потому что это дерьмовый графический интерфейс, делающий случайное дерьмо, мы его не спрашиваем - однако он совершенно корректен из командной строки или PHP mysqli -
START TRANSACTION;
BEGIN;
INSERT into test (b) VALUES ('1'),('2'),('3');
SELECT LAST_INSERT_ID() AS lastid,ROW_COUNT() AS rowcount;
COMMIT;
В PHP это выглядит так (local_sqle - это прямой вызов mysqli_query, local_sqlec - это вызов mysqli_query + convert resultset для массива PHP):
local_sqle("START TRANSACTION;
BEGIN;
INSERT into test (b) VALUES ('1'),('2'),('3');");
$r=local_sqlec("SELECT LAST_INSERT_ID() AS lastid,ROW_COUNT() AS rowcount;");
local_sqle("
COMMIT;");
$i=0;
echo "last id =".($r[0]['lastid'])."<br>";
echo "Row count =".($r[0]['rowcount'])."<br>";
while($i<$r[0]['rowcount']){
echo "inserted id =".($r[0]['lastid']+$i)."<br>";
$i++;
}
Причина, по которой запросы разделены, заключается в том, что я иначе не получал бы результат с помощью своих собственных функций, если вы делаете это со стандартными функциями, вы можете вернуть его в один оператор, а затем получить нужный результат (он должен be result number 2 - при условии, что вы используете расширение, которое обрабатывает несколько результирующих наборов/запросов).
Ответ 5
Я не был бы уверен, что значение автоинкремента увеличит элемент на 1. и возникнут огромные проблемы, если ваша БД будет иметь репликацию Master//Master и разрешить исключение дубликатов auto_increment. ИИ будет +2 вместо +1, также, если будет еще один мастер, он придет в +3. так что ретрансляция таких вещей, как AUTO_INCREMENT, увеличивается на 1 и убивает ваш проект.
Я вижу только несколько хороших вариантов для этого.
этот фрагмент SQL не будет иметь проблем с несколькими мастерами и будет давать хорошие результаты, пока вам не понадобятся только вставленные записи. по нескольким запросам без транзакций можно ловить другие записи вставок.
START TRANSACTION;
SELECT max(id) into @maxLastId FROM 'main_table';
INSERT INTO 'main_table' ('value') VALUES ('first'), ('second') ON DUPLICATE KEY UPDATE 'value' = VALUES('value');
SELECT 'id' FROM 'main_table' WHERE id > @maxLastId OR @maxLastId IS NULL;
COMMIT;
(если вам также понадобятся обновленные записи с помощью DUPLICATE KEY UPDATE), вам потребуется немного реорганизовать базу данных, и SQL будет выглядеть следующим образом (безопасно для транзакций и без транзакций внутри одного соединения.)
#START TRANSACTION
INSERT INTO bulk_inserts VALUES (null);
SET @blukTransactionId = LAST_INSERT_ID();
SELECT @blukTransactionId, LAST_INSERT_ID();
INSERT INTO 'main_table' ('value', 'transaction_id') VALUES ('first', @blukTransactionId), ('second', @blukTransactionId) ON DUPLICATE KEY UPDATE 'value' = VALUES('value'), 'transaction_id' = VALUES('transaction_id');
SELECT @blukTransactionId, LAST_INSERT_ID();
SELECT id FROM 'main_table' WHERE 'transaction_id' = @blukTransactionId;
#COMMIT
оба случая безопасны для транснациональных. первая покажет вам только вставленные записи, а вторая покажет все записи, даже обновленные.
также эти параметры будут работать даже с INSERT IGNORE...
Ответ 6
$query = "INSERT INTO TABLE (ID,NAME,EMAIL) VALUES (NULL,VALUE1, VALUE2)";
$idArray = array();
foreach($array as $key) {
mysql_query($query);
array_push($idArray, mysql_insert_id());
}
print_r($idArray);