Як я можу вставити багато рядків у таблицю MySQL і повернути нові ідентифікатори?


77

Зазвичай я можу вставити рядок у таблицю MySQL і отримати last_insert_idназад. Тепер я хочу масово вставити багато таблиць у таблицю та повернути масив ідентифікаторів. Хтось знає, як я можу це зробити?

Є кілька подібних питань, але вони не зовсім однакові. Я не хочу вставляти новий ідентифікатор у будь-яку тимчасову таблицю; Я просто хочу повернути масив ідентифікаторів.

Чи можу я отримати lastInsertId із масивної вставки?

Mysql багаторядний рядок вставки-вибору з last_insert_id ()


Чому ви не можете вставити їх по одному?
санмай

Вам потрібно імітувати OUTPUTречення. Я вважаю, що ви можете зробити це за допомогою тригера в MySQL
Мартін Сміт

Ви не можете використовувати групове вставлення, а потім функцію lime last_insert_id (), це не працює.
NB

можливий дублікат речення OUTPUT у mysql
Мартін Сміт

4
Ні - цей метод має недоліки теж - якщо ви не звернути вставку в LOCK TABLES ... НАПИШІТЬ, і ви також повинні дозволити auto_increment_increment
symcbean

Відповіді:


78

Старий потік, але щойно розглянув це, отже: якщо ви використовуєте InnoDB в останній версії MySQL, ви можете отримати список ідентифікаторів за допомогою LAST_INSERT_ID()та ROW_COUNT().

InnoDB гарантує послідовні номери для АВТОМАТИЧНОГО ЗБІЛЬШЕННЯ під час масових вставок, якщо innodb_autoinc_lock_modeвстановлено значення 0 (традиційне) або 1 (послідовне). Отже, ви можете отримати перший ідентифікатор від LAST_INSERT_ID()і останній , додавши ROW_COUNT()-1.


6
Вам потрібна транзакція? Що робити, якщо інші вставки потрапляють посередині?

3
Поки ви використовуєте механізм InnoDB і переконуєтесь, що блокування auto_increment увімкнено (що може призвести до зниження продуктивності), явне визначення транзакції не потрібно. Оскільки InnoDB виконує блокування під час вставки, інші вставки повинні чекати закінчення вставки. Подивіться на dev.mysql.com/doc/refman/5.1/en/…
Dag Sondre Hansen

1
MyISAM не є транзакційним db-двигуном, і, отже, інші вставки можуть відбуватися, поки триває об'ємна вставка, переплутавши послідовність. Блокування може запобігти цьому (хоча не надто впевнений), але одне з розв’язань, яке я знайшов, задокументоване MySQL, є описаним вище.
Dag Sondre Hansen

1
@Wulf Я припускаю (припустимо, підкреслено) це стосується ВСТАВКИ, ЗАВАНТАЖЕННЯ ДАНИХ, ЗАМІНИ ВІД тощо.
Даг Сондре Хансен,

1
Я думаю, що також важливо зазначити, що якщо ви покладаєтесь на такий метод, щоб отримати кілька ідентифікаторів вставки, ви не зможете використовувати мульти-майстер-кластери, наприклад, кластер Galera, якщо вам коли-небудь знадобиться така річ.
JohnK

17

Єдиний спосіб, я думаю, це можна зробити, це якщо ви зберігаєте унікальний ідентифікатор для кожного набору вставлених рядків (керівництво), а потім вибираєте ідентифікатори рядків. наприклад:

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

Ви також можете створити керівництво в базі даних за допомогою uuid()


4

Припустимо, у нас є таблиця, яка називається спокусливою, з двома колонками 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 >=@first_id;

#now that you are done don't forget to unlock the table.
unlock tables;

0

Я думаю, вам доведеться обробляти ідентифікатор транзакції у вашій програмі або ідентифікатор товару у вашій програмі, щоб зробити це бездоганно.

Один із способів зробити це, який міг би спрацювати, припускаючи, що всі ваші вставки успішні (!), Є наступний:

Потім ви можете отримати вставлені ідентифікатори з циклом для кількості уражених рядків, починаючи з 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 + перетворення набору результатів у масив 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++;
}

Причина, за якою запити розділяються, полягає в тому, що в іншому випадку я б не отримав свій результат, використовуючи власні функції, якщо ви робите це зі стандартними функціями, ви можете повернути його назад в одне твердження, а потім отримати потрібний результат (це повинен бути номер результату 2 - припускаючи, що ви використовуєте розширення, яке обробляє більше одного набору результатів / запиту).


0

Я не був би впевнений, що значення автоматичного приросту збільшить елемент на 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 ...


0

Ця тема застаріла, але всі ці рішення мені не допомогли, тому я придумав своє.

Спочатку порахуйте, скільки рядків потрібно вставити

припустимо, нам потрібно додати 5 рядків:

LOCK TABLE tbl WRITE;

SELECT `AUTO_INCREMENT` FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'my_db' AND TABLE_NAME   = 'tbl'

потім використовуйте щойно вибраний auto_increment, щоб зробити наступний запит:

ALTER TABLE tbl AUTO_INCREMENT = {AUTO_INCREMENT}+5;
UNLOCK TABLES;

Нарешті зробіть свої вставки

Використовуйте зарезервований діапазон автоматичного збільшення для вставки з ідентифікатором.

Увага: це рішення вимагає підвищеного рівня доступу до таблиць. Але зазвичай групові вставки виконуються кронами та сценаріями імпортера, а що не, може використовувати спеціальний доступ у будь-якому випадку. Ви не використовували б це лише для кількох вставок.

Це може залишити невикористані ідентифікатори, якщо ви використовуєте ПОВТОРЕННЕ КЛЮЧОВЕ ОНОВЛЕННЯ.


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

3
це не масовий запит на вставку.
Peacemoon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.