Как получить ID последней обновленной строки в MySQL?

135

Как с помощью PHP получить идентификатор последней обновленной строки в MySQL?

Авинаш
источник
2
mysqli_insert_id ($ link) вернет в точности идентификатор последней обновленной строки. Я использую эту функцию в своих проектах с той же целью. Вы можете использовать его как в синхронных, так и в асинхронных запросах. Просто вставьте $ lastupdated_row_id = mysqli_insert_id ($ link) в ваш код, и он будет работать для вас.
Наим Уль Ваххаб
1
Разве вы еще не знаете идентификатор строки при обновлении? Думаю, в некоторых случаях этого не происходит.
JCharette
1
Вы, вероятно, используете предложение where в своем запросе на обновление, почему вы не можете использовать то же предложение where в запросе select? 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;

РЕДАКТИРОВАТЬ по aefxx

Этот метод может быть дополнительно расширен для получения идентификатора каждой строки, затронутой оператором обновления:

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

Это вернет строку со всеми идентификаторами, объединенными запятой.

Pomyk
источник
6
Не могу поверить, что у этого было 0 голосов, а комментарий mysql_insert_id (), который вообще не то, что запрашивал OP, имеет 13. Спасибо, Pomyk, умный трюк!
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 для более подробной информации.
Joel
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, проверяющего, будут ли данные изменяться в строке.

newtover
источник
3
Это безопасно для многих пользователей, поскольку несколько клиентов могут выполнить оператор UPDATE и получить собственное значение последовательности с помощью оператора SELECT (или mysql_insert_id ()), не затрагивая и не подвергаясь влиянию других клиентов, которые генерируют свои собственные значения последовательности. Согласно dev.mysql.com/doc/refman/5.0/en/…
brutuscat
1
Разве это не установит для item_id последнюю вставленную запись?
arleslie 02
2
@arleslie, если вы перейдете по ссылке на документы в комментарии выше, вы увидите, что это не так. Это предполагаемое поведение именно для этого случая.
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 установить его внутреннюю переменную на ID найденной строки. Когда вы передаете значение, last_insert_id(expr)подобное этому, оно в конечном итоге возвращает это значение, которое в случае таких идентификаторов, как здесь, всегда является положительным целым числом и, следовательно, всегда оценивается как истинное, никогда не вмешиваясь в предложение where. Это работает, только если какая-то строка действительно была найдена, поэтому не забудьте проверить затронутые строки. Затем вы можете получить идентификатор несколькими способами.

MySQL last_insert_id()

Вы можете генерировать последовательности без вызова LAST_INSERT_ID (), но полезность использования функции таким образом заключается в том, что значение 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();
}

(К вашему сведению, этот класс 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 vs PostgreSQL: Добавление столбца «Время последнего изменения» в таблицу и Руководства по MySQL: Сортировка строк . Я только что собрал.

Чад фон Нау
источник
7
Этот метод может получить неправильный идентификатор, если вторая вставка выполняется сразу после первого запроса вставки. Однако, если мы используем «WHERE» с этим запросом, то есть SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1 WHERE (некоторые условия, связанные с последним запросом вставки), то это может предотвратить выборку неправильного идентификатора.
Naeem Ul Wahhab
1
@ TheNoble-Coder Это правда. Если вам нужно получить идентификатор строки, затронутой конкретным запросом на обновление, используйте технику Pomyk. Этот метод здесь более полезен при асинхронном использовании, когда вам просто нужно абсолютное последнее обновление.
Chad von Nau
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 . [Источник]

Anon30
источник
Привет спасибо То, что они имеют в виду, на самом деле более интересно, чем принятый ответ выше.
Green
2

Эй, просто нужна была такая уловка - решил по-другому, может у тебя сработает. Обратите внимание, что это не масштабируемое решение, и оно будет очень плохим для больших наборов данных.

Разделите свой запрос на две части -

сначала выберите идентификаторы строк, которые вы хотите обновить, и сохраните их во временной таблице.

во-вторых, выполните исходное обновление, изменив условие в операторе обновления на where id in temp_table.

И для обеспечения параллелизма вам необходимо заблокировать таблицу перед этими двумя шагами, а затем снять блокировку в конце.

Опять же, это работает для меня для запроса, который заканчивается на limit 1, поэтому я даже не использую временную таблицу, а вместо этого просто переменную для хранения результата первой select.

Я предпочитаю этот метод, так как знаю, что всегда буду обновлять только одну строку, а код прост.

olamundo
источник
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 (это был капля) Кстати, большое спасибо за ответ Pomyk!

Gromish
источник
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

Если вы только делаете вставки и хотите одну из той же сессии, сделайте так, как ответили peirix. Если вы вносите изменения, вам нужно будет изменить схему базы данных, чтобы сохранить, какая запись была недавно обновлена.

Если вам нужен идентификатор из последней модификации, которая могла быть из другого сеанса (т. Е. Не из того, что было выполнено только что запущенным PHP-кодом в данный момент, а из того, что было выполнено в ответ на другой запрос), вы можете добавить TIMESTAMP столбец в таблицу под названием LAST_MODIFIED (см http://dev.mysql.com/doc/refman/5.1/en/datetime.html для информации), а затем , когда вы обновляете, набор LAST_MODIFIED = CURRENT_TIME.

Установив это, вы можете использовать запрос, такой как: SELECT id ИЗ таблицы ORDER BY last_modified DESC LIMIT 1; чтобы получить последнюю измененную строку.

a1kmm
источник
-9

Нет необходимости в таком длинном коде Mysql. В PHP запрос должен выглядеть примерно так:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
Дриада
источник