Подтвердить что ты не робот

Как вставить много строк в таблицу MySQL и вернуть новые идентификаторы?

Обычно я могу вставить строку в таблицу MySQL и вернуть last_insert_id назад. Теперь, однако, я хочу, чтобы массив вставлял много строк в таблицу и возвращал массив идентификаторов. Кто-нибудь знает, как я могу это сделать?

Есть несколько подобных вопросов, но они не совсем то же самое. Я не хочу вставлять новый ID во временную таблицу; Я просто хочу вернуть массив идентификаторов.

Можно ли получить lastInsertId из объемной вставки?

Mysql mulitple row insert-select statement with last_insert_id()

4b9b3361

Ответ 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);