Como obter o ID da última linha atualizada no MySQL?

134

Como obtenho o ID da última linha atualizada no MySQL usando PHP?

Avinash
fonte
2
mysqli_insert_id ($ link) retornará exatamente o ID da última linha atualizada. Estou usando essa função em meus projetos para o mesmo propósito. Você pode usá-lo em consultas síncronas ou assíncronas. Basta inserir $ lastupdated_row_id = mysqli_insert_id ($ link) no seu código e ele funcionará para você.
Naeem Ul Wahhab
1
Você já não sabe o ID da linha se atualizar? Eu acho que deve haver alguns casos em que você não.
JCharette
1
Você provavelmente usa uma cláusula where na sua consulta de atualização. Por que não pode usar a mesma cláusula where na consulta de seleção? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1?
Salman A

Respostas:

236

Encontrei uma resposta para este problema :)

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 por aefxx

Essa técnica pode ser expandida ainda mais para recuperar o ID de cada linha afetada por uma instrução de atualização:

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

Isso retornará uma sequência com todos os IDs concatenados por vírgula.

Pomyk
fonte
6
Não posso acreditar que isso teve 0 votos positivos, e o comentário mysql_insert_id (), que não é o que o OP estava perguntando, tem 13. Obrigado Pomyk, um truque inteligente!
Jaka Jančar 11/01
1
Como você tem uma WHEREcláusula, você pode simplesmente usar a mesma WHEREcláusula na sua próxima consulta.SELECT id FROM footable WHERE fooid > 5
Salman A
4
Talvez todo mundo entenda isso, mas se você usar mysql_query (); você precisa dividir isso em três chamadas diferentes, mas funcionará.
22812 rael_kid
8
Não há necessidade de usar variáveis. LAST_INSERT_ID()pode aceitar um argumento que definirá o valor retornado pela próxima chamada para LAST_INSERT_ID(). Por exemplo: UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. Agora, SELECT LAST_INSERT_ID();retornará o ID atualizado. Veja a resposta de newtover para mais detalhes.
Joel
3
@SteveChilds Acabei de comentar a pergunta de newtover e quero adicionar uma solução para a armadilha que você está descrevendo. Isso define LAST_INSERT_ID a 0 se não há nada para UPDATE: UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);. No entanto, ele não recupera vários IDs, portanto, essa resposta é superior.
martinczerwi
33

Estou surpreso que, dentre as respostas, não vejo a solução mais fácil.

Suponha que item_idseja uma coluna de identidade inteira na itemstabela e você atualize as linhas com a seguinte instrução:

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

Para conhecer a última linha afetada logo após a instrução, atualize-a levemente para o seguinte:

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

Se você precisar atualizar apenas uma linha realmente alterada, será necessário adicionar uma atualização condicional do item_id por meio da verificação de LAST_INSERT_ID se os dados serão alterados na linha.

newtover
fonte
3
É seguro para vários usuários porque vários clientes podem emitir a instrução UPDATE e obter seu próprio valor de sequência com a instrução SELECT (ou mysql_insert_id ()), sem afetar ou ser afetado por outros clientes que geram seus próprios valores de sequência. Como dev.mysql.com/doc/refman/5.0/en/…
brutuscat
1
Isso não definirá o item_id para o último registro inserido?
arleslie
2
@ arleslie, se você seguir o link para os documentos no comentário do brutuscat acima, verá que não. Esse é o comportamento pretendido exatamente para o caso.
newtover 4/08/14
1
Esta é realmente a resposta correta. Embora a consulta pareça um pouco contra-intuitiva, é exatamente isso que a documentação do MySQL diz para fazer.
Timothy Zorn
3
Caso a consulta esteja confundindo você, uma vez que LAST_INSERT_ID (expr) retornará o valor de expr para a chamada UPDATE, você também poderá usá-lo desta forma:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi
14

Isso é oficialmente simples, mas notavelmente contra-intuitivo. Se você estiver fazendo:

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

Altere para este:

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

A adição de last_insert_id(user_id)na wherecláusula está dizendo ao MySQL para definir sua variável interna para o ID da linha encontrada. Quando você passa um valor para last_insert_id(expr)esse valor , ele retorna esse valor, que no caso de IDs como esse sempre é um número inteiro positivo e, portanto, sempre é avaliado como verdadeiro, nunca interferindo na cláusula where. Isso funciona apenas se alguma linha foi realmente encontrada; lembre-se de verificar as linhas afetadas. Você pode obter o ID de várias maneiras.

MySQL last_insert_id()

Você pode gerar sequências sem chamar LAST_INSERT_ID (), mas o utilitário de usar a função dessa maneira é que o valor do ID seja mantido no servidor como o último valor gerado automaticamente. É seguro para vários usuários porque vários clientes podem emitir a instrução UPDATE e obter seu próprio valor de sequência com a instrução SELECT (ou mysql_insert_id ()), sem afetar ou ser afetado por outros clientes que geram seus próprios valores de sequência.

MySQL mysql_insert_id()

Retorna o valor gerado para uma coluna AUTO_INCREMENT pela instrução INSERT ou UPDATE anterior. Use esta função depois de executar uma instrução INSERT em uma tabela que contém um campo AUTO_INCREMENT ou usar INSERT ou UPDATE para definir um valor de coluna com LAST_INSERT_ID (expr).

O motivo das diferenças entre LAST_INSERT_ID () e mysql_insert_id () é que LAST_INSERT_ID () é fácil de usar em scripts, enquanto mysql_insert_id () tenta fornecer informações mais precisas sobre o que acontece com a coluna AUTO_INCREMENT.

PHP mysqli_insert_id()

A execução de uma instrução INSERT ou UPDATE usando a função LAST_INSERT_ID () também modificará o valor retornado pela função mysqli_insert_id ().

Juntando tudo:

$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 que classe DB está aqui .)

Vladimir Kornea
fonte
Importante notar: este é seguro para várias conexões; o valor persistente para last_insert_id ou mysql_insert_id (e talvez mysqli_insert_id, não verifiquei) são por conexão. Impressionante!
Ryan S
10

Esse é o mesmo método da resposta de Salman A, mas aqui está o código que você realmente precisa fazer.

Primeiro, edite sua tabela para que ela acompanhe automaticamente sempre que uma linha for modificada. Remova a última linha se você quiser saber apenas quando uma linha foi inserida inicialmente.

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

Em seguida, para descobrir a última linha atualizada, você pode usar esse código.

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

Todo esse código foi retirado do MySQL vs PostgreSQL: Adicionando uma coluna 'Last Modified Time' a uma tabela e Manual do MySQL: Classificando Linhas . Acabei de montar.

Chad von Nau
fonte
7
Esse método pode buscar a identificação incorreta se a segunda inserção for feita logo após a primeira consulta de inserção. No entanto, se usarmos 'WHERE' com esta consulta, ou seja, SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1 WHERE (algumas condições relacionadas à última consulta de inserção), isso pode impedir a busca do id errado.
Naeem Ul Wahhab
1
@ TheNoble-Coder Isso é verdade. Se você precisar que o ID de uma linha afetou uma consulta de atualização específica, use a técnica de Pomyk. Essa técnica aqui é mais útil quando usada de forma assíncrona, onde você deseja apenas a última atualização absoluta.
Chad von Nau
5

Inquerir :

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

Função PHP:

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

É trabalho para mim;)

GigolNet Guigolachvili
fonte
eu gostei mesmo, mas correu differntly ref: forums.mysql.com/read.php?52,390616,390619
3

Mais ainda para a resposta acima aceita
Para aqueles que estavam se perguntando sobre :=&=

Diferença significativa entre :=e =, e é isso que :=funciona como um operador de atribuição de variável em qualquer lugar, enquanto =só funciona dessa maneira nas instruções SET e é um operador de comparação em qualquer outro lugar.

Portanto SELECT @var = 1 + 1;, @varpermanecerá inalterado e retornará um booleano (1 ou 0, dependendo do valor atual de @var), enquanto SELECT @var := 1 + 1;mudará @varpara 2 e retornará 2 . [Fonte]

Anon30
fonte
Ei, obrigado. O que eles querem dizer é realmente mais interessante do que a resposta aceita acima.
Verde
2

Ei, eu só precisava de um truque - resolvi de uma maneira diferente, talvez funcione para você. Observe que essa não é uma solução escalável e será muito ruim para grandes conjuntos de dados.

Divida sua consulta em duas partes -

primeiro, selecione os IDs das linhas que você deseja atualizar e armazene-os em uma tabela temporária.

em segundo lugar, faça a atualização original com a condição na instrução de atualização alterada para where id in temp_table.

E para garantir a simultaneidade, você precisa bloquear a tabela antes dessas duas etapas e soltar a trava no final.

Novamente, isso funciona para mim, para uma consulta que termina com limit 1, então nem uso uma tabela temporária, mas simplesmente uma variável para armazenar o resultado da primeira select.

Prefiro esse método, pois sei que sempre atualizarei apenas uma linha e o código é direto.

olamundo
fonte
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;

Eu tive que CAST o id (não sei por que) ... ou não consigo obter o conteúdo @uids (era um blob) Btw muito obrigado pela resposta Pomyk!

Gromish
fonte
2

O ID da última linha atualizada é o mesmo que você usa no 'updateQuery' para encontrar e atualizar essa linha. Portanto, salve (ligue) esse ID da maneira que desejar.

last_insert_id()depende do AUTO_INCREMENT, mas o último ID atualizado não.

Driada
fonte
3
E se a atualização não for feita a partir de um ID, mas outro conjunto de atributos?
Sebas
2

Minha solução é, primeiro decida o "id" (@uids) com o comando select e depois atualize esse id com @uids.

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

funcionou no meu projeto.

Ahmet Uğur
fonte
1

Se você está apenas inserindo e deseja uma da mesma sessão, faça conforme a resposta da peirix. Se você estiver fazendo modificações, precisará modificar o esquema do banco de dados para armazenar qual entrada foi atualizada mais recentemente.

Se você deseja o ID da última modificação, que pode ter sido de uma sessão diferente (por exemplo, não aquela que foi feita apenas pelo código PHP em execução no momento, mas que foi feita em resposta a uma solicitação diferente), você pode adicionar um TIMESTAMP na sua tabela chamada last_modified (consulte http://dev.mysql.com/doc/refman/5.1/en/datetime.html para obter informações) e, quando você atualizar, defina last_modified = CURRENT_TIME.

Depois de definir isso, você poderá usar uma consulta como: SELECT id FROM tabela ORDER BY last_modified DESC LIMIT 1; para obter a linha modificada mais recentemente.

a1kmm
fonte
-9

Não há necessidade de tanto tempo código Mysql. No PHP, a consulta deve ser algo como isto:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
Driada
fonte