Отримати новий ідентифікатор первинного ключа запису з запиту на вставку mysql?


249

Гаразд, так скажемо, що я роблю mysql INSERTв одну з моїх таблиць, а в таблиці є стовпець, на item_idякий встановлено autoincrementі primary key.

Як я можу отримати запит для виведення значення новоствореного первинного ключа item_idв одному запиті?

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

Якщо це неможливо, то яка найкраща практика для отримання правильного ідентифікатора?


1
Немає можливості повернути що-небудь із такого INSERTзапиту; чому ви вважаєте, що це може призвести до неправильного результату?
Вибухові таблетки

4
Ну, якщо процес виконується двома людьми окремо, то ви можете отримати список, що перекривається, я думаю - оскільки вам доведеться виконати 2 окремих запити?
Емі Невіл


@JimFell так, це в основному те саме питання, але в цілому є набагато кращі відповіді
RozzA

1
Використовуйте postgresql, тоді зробіть так, як ця таблиця INSERT INTO (col1, col2) VALUES (val1, val2) ID ВІДПРОВАДЖЕННЯ або ВСТАВЛЕННЯ INTO (col1, col2) VALUES (val1, val2) RETURNING * або UPDATE table SET col1 = val1, col2 = val2 WHERE оператор RETURNING id або UPDATE таблиця SET (col1, col2) = (val1, val2) WHERE оператор RETURNING id або UPDATE SET SET (col1, col2) = (val1, val2) WHERE заявка RETURNING *
gdarcan

Відповіді:


327

Вам потрібно використовувати LAST_INSERT_ID()функцію: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id

Наприклад:

INSERT INTO table_name (col1, col2,...) VALUES ('val1', 'val2'...);
SELECT LAST_INSERT_ID();

Це поверне вам PRIMARY KEYзначення останнього рядка, який ви вставили:

Створений ідентифікатор підтримується на сервері на основі кожного з'єднання . Це означає, що значення, повернене функцією для даного клієнта, є першим значенням AUTO_INCREMENT, сформованим для останнього оператора, що впливає на стовпець AUTO_INCREMENT цим клієнтом .

Таким чином, значення , що повертається LAST_INSERT_ID()в кожного користувача і не впливає на інші запити , які можуть бути запущені на сервері від інших користувачів .


8
так, але що робити, якщо у проміжку (між запитами у списку процесів) вставлено інший рядок? Чи є спосіб написати запит на вставку, щоб він виводив це?
Емі Невіл

Гаразд, я бачу ... останній ідентифікатор вставки запиту записується, навіть якщо він не входить у результат ... $ mysqli-> insert_id
Емі Невіл

27
Це поверне вам PRIMARY KEYзначення останнього рядка, який ви вставили, оскільки це за з'єднання - кожне з'єднання з сервером зберігатиме для цього власне значення. Я оновив відповідь, щоб уточнити це.
Замок Дункана

Тож припустимо, що 3 користувачі одночасно розмістили свої форми, і моя база даних повинна ввести їх. Я хочу додати рядок, відповідний кожному новоствореному ідентифікатору table1 в table2. Чи забезпечується паралельність або мені доведеться це робити в PHP вручну, для запитів на вхід в базу даних?
bad_keypoints

Якщо в момент, коли ви робите вставку table1, база даних знає всю інформацію, яку ви хочете вставити в table2, то ви можете використовувати тригер для цього або об'єднати це в запит. Якщо ні, то вам потрібно буде використовувати кілька запитів - тобто робити це в PHP. Це залежить від того, які дані є і звідки вони надходять для другої вставки.
Блокування Дункана

21

ПОВЕРНУТИСЯ !! з "LAST_INSERT_ID ()", якщо намагається повернути це значення основного ключа в межах PHP.

Я знаю, що цей потік не позначений тегом php, але для тих, хто натрапив на цю відповідь, шукаючи повернути ідентифікатор вставки MySQL з сценарію вставки PHP, використовуючи стандартні виклики mysql_query - він звичайно не працює і не очевидний без фіксації помилок SQL.

Новіший mysqli підтримує кілька запитів - LAST_INSERT_ID () насправді є другим запитом від оригіналу.

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


7
LAST_INSERT_IDє функцією MySQL за з’єднання. Якщо ви запитуєте останній ідентифікатор вставки, можливо, окреме з'єднання виконало запис, і у вас буде неправильний ідентифікатор.
Вибухові таблетки

@ExplosionPills mysql_insert_id()також працює на основі підключення, але воно також зазнає дивної поведінки, як це бачиться тут stackoverflow.com/a/897374/1305910 у коментарі Cliffordlife - ніколи не маємо на mysqli
увазі, що

чи можете ви уточнити, що ви маєте на увазі, коли ви залишаєтесь "це звичайно не працює"?
John ktejik

18

З LAST_INSERT_ID()документації:

Створений ідентифікатор підтримується на сервері на основі кожного з'єднання

Тобто, якщо у вас одночасно є два окремі запити до сценарію, вони не впливатимуть один на одного LAST_INSERT_ID()(якщо, можливо, ви не використовуєте стійке з'єднання).


2
Я думаю, що сумнівно, якщо у вашій таблиці є тригер, який робить вставку в іншу таблицю .... LAST_INSERT_ID () поверне значення id іншої таблиці ..
bgies

15

Ось що ви шукаєте !!!

select LAST_INSERT_ID()

Це найкраща альтернатива SCOPE_IDENTITY()функції, яка використовується в SQL Server.

Ви також повинні мати на увазі, що це буде працювати лише в тому випадку, якщо Last_INSERT_ID()за вашим Insertзапитом буде звільнено . Тобто запит повертає ідентифікатор, вставлений у схему. Ви не можете отримати останній вставлений ідентифікатор конкретної таблиці.

Для отримання детальної інформації перейдіть за посиланням Еквівалент функції SQLServer SCOPE_IDENTITY () в mySQL?


6

Якщо вам потрібно значення, перш ніж вставити рядок:

CREATE FUNCTION `getAutoincrementalNextVal`(`TableName` VARCHAR(50))
    RETURNS BIGINT
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN

    DECLARE Value BIGINT;

    SELECT
        AUTO_INCREMENT INTO Value
    FROM
        information_schema.tables
    WHERE
        table_name = TableName AND
        table_schema = DATABASE();

    RETURN Value;

END

Ви можете використовувати це у вставці:

INSERT INTO
    document (Code, Title, Body)
VALUES (                
    sha1( concat (convert ( now() , char), ' ',   getAutoincrementalNextval ('document') ) ),
    'Title',
    'Body'
);

1
Це не здається гарною ідеєю? Якщо 2 клієнта зателефонують до цієї функції одночасно, вони подумають, що вони вставляють той самий ідентифікатор, коли насправді їх немає .... один буде трохи повільніше вставляти і отримувати наступний ідентифікатор, не знаючи про це.
CarCar

5

Ви отримаєте ці параметри в результаті запиту:

    "fieldCount": 0,
    "affectedRows": 1,
    "insertId": 66,
    "serverStatus": 2,
    "warningCount": 1,
    "message": "",
    "protocol41": true,
    "changedRows": 0

Це insertIdсаме те, що вам потрібно.

(NodeJS-mySql)



2

просто використовуйте "$ last_id = mysqli_insert_id ($ conn);"


2
Я насправді натрапив сюди, шукаючи php-версії цієї відповіді завдяки Google, тому я проголосував за цю відповідь. Хоча технічно ОП не просив php, це може бути корисним для багатьох людей, які натрапляють і тут.
Фотограф Бріт

Дуже дякую Арнаву! Я
ХуанСедано

1

Якщо ви використовуєте PHP: На об'єкт PDO ви можете просто викликати метод lastInsertId після вставки.

Інакше за допомогою LAST_INSERT_ID можна отримати таке значення:SELECT LAST_INSERT_ID();



0

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

створити випадковий ключ і вставити його в таблицю, створивши новий рядок. тоді ви можете скористатися цим ключем для отримання первинного ключа. використовуйте оновлення для додавання даних та інших речей.

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

Я дійсно не рекомендую цього, якщо у вас немає інших варіантів.

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