Як отримати ідентифікатор останнього оновленого рядка в MySQL?


134

Як отримати ідентифікатор останнього оновленого рядка в MySQL за допомогою PHP?


2
mysqli_insert_id ($ link) поверне точно ідентифікатор останнього оновленого рядка. Я використовую цю функцію у своїх проектах з тією ж метою. Ви можете використовувати його як у синхронних, так і в асинхронних запитах. Просто вставте у свій код $ lastupdate_row_id = mysqli_insert_id ($ посилання), і воно буде працювати для вас.
Naeem Ul Wahhab

1
Ви вже не знаєте ідентифікатора рядка, якщо оновите? Я думаю, що мають бути випадки, коли цього не робиш.
JCharette

1
Ви, ймовірно, використовуєте пункт де у запиті оновлення, чому ви не можете використати те саме, де у виборі запиту? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1?
Салман

Відповіді:


236

Я знайшов відповідь на цю проблему :)

SET @update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT @update_id := id)
WHERE some_other_column = 'blah' LIMIT 1; 
SELECT @update_id;

EDIT від aefxx

Цю методику можна додатково розширити, щоб отримати ідентифікатор кожного рядка, на який впливає оператор оновлення:

SET @uids := null;
UPDATE footable
   SET foo = 'bar'
 WHERE fooid > 5
   AND ( SELECT @uids := CONCAT_WS(',', fooid, @uids) );
SELECT @uids;

Це поверне рядок із усіма ідентифікаторами, об'єднаними комою.


6
Не можу повірити, що це було 0 оновлених результатів, а коментар mysql_insert_id (), який зовсім не те, про що просив ОП, має 13. Спасибі Помик, розумний трюк!
Jaka Jančar

1
Оскільки у вас є WHEREпункт, ви можете просто використати той самий WHEREпункт у своєму наступному запитіSELECT id FROM footable WHERE fooid > 5
Salman A

4
Можливо, всі це розуміють, але якщо ви використовуєте mysql_query (); Ви повинні розділити це на три різні дзвінки, але це спрацює.
rael_kid

8
Не потрібно навіть використовувати змінні. LAST_INSERT_ID()може прийняти аргумент, який встановить значення, повернене наступним викликом LAST_INSERT_ID(). Наприклад: UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. Тепер SELECT LAST_INSERT_ID();повернеться оновлений ідентифікатор. Дивіться відповідь newtover для більш детальної інформації.
Джоел

3
@SteveChilds Я просто коментував питання newtover і хочу додати рішення до проблеми, яку ви описуєте. Це встановлює last_insert_id 0 , якщо немає нічого UPDATE: UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);. Однак він не отримує декілька ідентифікаторів, тому ця відповідь є вищою.
martinczerwi

33

Гм, я здивований, що серед відповідей я не бачу найпростішого рішення.

Припустимо, item_idце цілий стовпець ідентичності в itemsтаблиці, і ви оновлюєте рядки наступним твердженням:

UPDATE items
SET qwe = 'qwe'
WHERE asd = 'asd';

Потім, щоб знати останню порушений рядок відразу після оператора, слід трохи оновити його на наступне:

UPDATE items
SET qwe = 'qwe',
    item_id=LAST_INSERT_ID(item_id)
WHERE asd = 'asd';
SELECT LAST_INSERT_ID();

Якщо вам потрібно оновити лише дійсно змінений рядок, вам потрібно буде додати умовне оновлення item_id через LAST_INSERT_ID перевірку, чи будуть дані зміни в рядку.


3
Це безпека для багатьох користувачів, тому що кілька клієнтів можуть видавати оператор UPDATE і отримувати власне значення послідовності за допомогою оператора SELECT (або mysql_insert_id ()), не впливаючи та не впливаючи на інших клієнтів, які генерують власні значення послідовності. Відповідно до dev.mysql.com/doc/refman/5.0/en/…
brutuscat

1
Чи не встановить цей елемент item_id останньою вставленою записом?
arleslie

2
@arleslie, якщо ви перейдете за посиланням на документи в коментарі brutuscat вище, ви побачите, що це не стане. Це призначена поведінка саме для конкретного випадку.
newtover

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

3
У випадку, якщо запит вас бентежить, оскільки LAST_INSERT_ID (expr) поверне значення expr для UPDATE-дзвінка, ви можете також використовувати його так:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi

14

Це офіційно просто, але надзвичайно інтуїтивно зрозуміло. Якщо ви робите:

update users set status = 'processing' where status = 'pending'
limit 1

Змініть це на це:

update users set status = 'processing' where status = 'pending'
and last_insert_id(user_id) 
limit 1

Додавання last_insert_id(user_id)цього whereпункту вказує MySQL встановити свою внутрішню змінну на ідентифікатор знайденого рядка. Коли ви передаєте таке значення, last_insert_id(expr)як це, воно в кінцевому підсумку повертає це значення, яке у випадку ідентифікаторів, як тут, завжди є цілим числом і, отже, завжди оцінюється як істинне, ніколи не втручаючись у пункт де. Це працює лише в тому випадку, якщо якийсь рядок був дійсно знайдений, тому не забудьте перевірити порушені рядки. Потім ви можете отримати ідентифікатор декількома способами.

MySQL last_insert_id()

Ви можете генерувати послідовності, не викликаючи LAST_INSERT_ID (), але корисністю використання функції таким чином є те, що значення ідентифікатора підтримується на сервері як останнє автоматично сформоване значення. Це безпека для багатьох користувачів, тому що кілька клієнтів можуть видавати оператор UPDATE і отримувати власне значення послідовності за допомогою оператора SELECT (або mysql_insert_id ()), не впливаючи та не впливаючи на інших клієнтів, які генерують власні значення послідовності.

MySQL mysql_insert_id()

Повертає значення, сформоване для стовпця AUTO_INCREMENT попереднім оператором INSERT або UPDATE. Використовуйте цю функцію після того, як ви виконали оператор INSERT в таблицю, яка містить поле AUTO_INCREMENT, або використали INSERT або UPDATE для встановлення значення стовпця з LAST_INSERT_ID (expr).

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

PHP mysqli_insert_id()

Виконання оператора INSERT або UPDATE за допомогою функції LAST_INSERT_ID () також змінить значення, повернене функцією mysqli_insert_id ().

Збираємо все це разом:

$affected_rows = DB::getAffectedRows("
    update users set status = 'processing' 
    where status = 'pending' and last_insert_id(user_id) 
    limit 1"
);
if ($affected_rows) {
    $user_id = DB::getInsertId();
}

(FYI, що тут клас DB .)


Важливо зауважити: це безпечне підключення до кількох з'єднань, збережене значення для last_insert_id або mysql_insert_id (і, можливо, mysqli_insert_id, я не перевіряв), є за з'єднання. Дивовижно!
Ryan S

11

Це той самий метод, що і у відповіді Салмана А, але ось код, який вам потрібно це зробити.

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

ALTER TABLE mytable
ADD lastmodified TIMESTAMP 
    DEFAULT CURRENT_TIMESTAMP 
    ON UPDATE CURRENT_TIMESTAMP;

Потім, щоб дізнатися останній оновлений рядок, ви можете використовувати цей код.

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

Цей код знято з MySQL проти PostgreSQL: Додавання стовпця "Останній змінений час" до таблиці та Посібнику для MySQL: сортування рядків . Я просто зібрав це.


7
Цей метод може отримати неправильний ідентифікатор, якщо друга вставка виконана відразу після першого запиту. Однак якщо ми використовуємо "WHERE" з цим запитом, тобто SELECT id FROM mytable ORDER by lastmodified DESC LIMIT 1 WHERE (деякі умови, пов’язані з останнім запитом вставки), то це може запобігти вибору неправильного ідентифікатора.
Naeem Ul Wahhab

1
@ TheNoble-Coder Це правда. Якщо вам потрібно, щоб ідентифікатор рядка впливав на конкретний запит оновлення, то використовуйте техніку Pomyk. Ця методика тут більш корисна при використанні асинхронно, де ви просто хочете абсолютного останнього оновлення.
Чад фон Нау

5

Запит:

$sqlQuery = "UPDATE 
            update_table 
        SET 
            set_name = 'value' 
        WHERE 
            where_name = 'name'
        LIMIT 1;";

Функція PHP:

function updateAndGetId($sqlQuery)
{
    mysql_query(str_replace("SET", "SET id = LAST_INSERT_ID(id),", $sqlQuery));
    return mysql_insert_id();
}

Це для мене робота;)


Мені сподобалося те саме, але побіжно

3

Далі до вищеприйнятого відповіді
Для тих, хто цікавився :=&=

Суттєва різниця між :=і =, і це в тому, що він :=працює як оператор присвоєння змінної скрізь, тоді =як працює лише таким чином у операторах SET і є оператором порівняння скрізь.

Так SELECT @var = 1 + 1;залишиться @varбез змін і поверне булеве значення (1 або 0 залежно від поточного значення @var), тоді як SELECT @var := 1 + 1;зміниться @varна 2 , а повернеться 2 . [Джерело]


Гей, дякую. Що вони означають, насправді цікавіше, ніж прийнята відповідь вище.
Зелений

2

Гей, мені просто потрібна була така хитрість - я вирішив її по-іншому, можливо, це допоможе тобі. Зверніть увагу, що це не масштабоване рішення, і це буде дуже погано для великих наборів даних.

Розділіть запит на дві частини -

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

по-друге, зробіть оригінальне оновлення з умовою в заяві оновлення, зміненою на where id in temp_table.

А щоб забезпечити одночасність, потрібно заблокувати таблицю перед цими двома кроками, а потім звільнити замок наприкінці.

Знову ж таки, це працює для мене, для запиту, який закінчується limit 1, тому я навіть не використовую тимчасову таблицю, а просто змінну, щоб зберігати результат першого select.

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


2
SET @uids := "";
UPDATE myf___ingtable
   SET id = id
   WHERE id < 5
  AND ( SELECT @uids := CONCAT_WS(',', CAST(id AS CHAR CHARACTER SET utf8), @uids) );
SELECT @uids;

Мені довелося закинути ідентифікатор (не знаю чому) ... або я не можу отримати вміст @uids (це була крапля) До речі, спасибі за відповідь Помика!


2

Ідентифікатор останнього оновленого рядка - той самий ідентифікатор, який ви використовуєте в 'updateQuery' для пошуку та оновлення цього рядка. Отже, просто збережіть (зателефонуйте) до цього ідентифікатора в будь-який інший момент.

last_insert_id()залежить від AUTO_INCREMENT, але останній оновлений ідентифікатор - ні.


3
Що робити, якщо оновлення проводиться не з ідентифікатора, а з іншого набору атрибутів?
Себас

2

Моє рішення: спочатку визначте "id" (@uids) за допомогою команди select і після цього оновіть ідентифікатор @uids.

SET @uids := (SELECT id FROM table WHERE some = 0 LIMIT 1);
UPDATE table SET col = 1 WHERE id = @uids;SELECT @uids;

це працювало над моїм проектом.


1

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

Якщо ви хочете, щоб ідентифікатор від останньої модифікації, яка могла відбуватися з іншого сеансу (тобто не з того, що тільки що було зроблено за допомогою PHP-коду, що працює в даний час, а з одного, зробленого у відповідь на інший запит), ви можете додати Стовпець TIMESTAMP до вашої таблиці називається last_modified (див. Http://dev.mysql.com/doc/refman/5.1/en/datetime.html для інформації), а потім, коли ви оновлюєте, встановіть last_modified = CURRENT_TIME.

Встановивши це, ви можете використовувати такий запит, як: SELECT id F від таблиці ORDER BY last_modified DESC LIMIT 1; щоб отримати останній змінений рядок.


-9

Немає необхідності в такому довгому коді Mysql. У PHP запит повинен виглядати приблизно так:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.