web-dev-qa-db-fra.com

Comment obtenir l'ID de la dernière ligne mise à jour dans MySQL?

Comment obtenir l'ID de la dernière ligne mise à jour dans MySQL avec PHP?

118
Avinash

J'ai trouvé une réponse à ce problème :)

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;

EDITpar aefxx

Cette technique peut être davantage développée pour récupérer l'ID de chaque ligne affectée par une instruction de mise à jour:

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

Cela retournera une chaîne avec tous les ID concaténés par une virgule.

215
Pomyk

Hm, je suis surpris que parmi les réponses, je ne vois pas la solution la plus simple.

Supposons que item_id soit une colonne d’identité entière dans la table items et que vous mettiez à jour les lignes avec l’instruction suivante:

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

Ensuite, pour connaître la dernière ligne affectée juste après l'instruction, vous devez légèrement mettre à jour l'instruction dans les éléments suivants:

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

Si vous devez mettre à jour uniquement la ligne réellement modifiée, vous devez ajouter une mise à jour conditionnelle de l'id_lément via la LAST_INSERT_ID pour vérifier si les données vont changer dans la ligne.

30
newtover

C'est la même méthode que la réponse de Salman A, mais voici le code dont vous avez réellement besoin pour le faire.

Commencez par éditer votre table afin qu’elle garde automatiquement la trace de chaque modification d’une ligne. Supprimez la dernière ligne si vous voulez seulement savoir quand une ligne a été initialement insérée.

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

Ensuite, pour connaître la dernière ligne mise à jour, vous pouvez utiliser ce code.

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

Ce code est entièrement extrait de MySQL vs PostgreSQL: Ajout d'une colonne 'Heure de la dernière modification' à une table et Manuel MySQL: Tri des lignes . Je viens de l'assembler.

10
Chad von Nau

C'est officiellement simple mais remarquablement contre-intuitif. Si vous faites:

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

Changez-le en ceci:

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

L'ajout de last_insert_id(user_id) dans la clause where indique à MySQL de définir sa variable interne avec l'ID de la ligne trouvée. Lorsque vous transmettez une valeur à last_insert_id(expr) comme ceci, elle renvoie cette valeur, qui dans le cas d'ID comme ici est toujours un entier positif et est donc toujours considérée comme vraie, sans jamais interférer avec la clause where. Cela ne fonctionne que si une ligne a été trouvée. Veillez donc à vérifier les lignes affectées. Vous pouvez alors obtenir l'ID de plusieurs manières.

MySQL last_insert_id()

Vous pouvez générer des séquences sans appeler LAST_INSERT_ID (), mais le L’utilité d’utiliser la fonction de cette façon est que la valeur de l’ID est conservés sur le serveur en tant que dernière valeur générée automatiquement. Il est multi-utilisateur sûr car plusieurs clients peuvent émettre le UPDATE et obtenez sa propre valeur de séquence avec l’instruction SELECT (ou mysql_insert_id ()), sans affecter ou être affecté par d’autres les clients qui génèrent leurs propres valeurs de séquence.

MySQL mysql_insert_id()

Renvoie la valeur générée pour une colonne AUTO_INCREMENT par le fichier instruction INSERT ou UPDATE précédente. Utilisez cette fonction après avoir eu exécuté une instruction INSERT dans une table contenant un Champ AUTO_INCREMENT, ou avez utilisé INSERT ou UPDATE pour définir une colonne valeur avec LAST_INSERT_ID (expr).

La raison des différences entre LAST_INSERT_ID () et mysql_insert_id () est que LAST_INSERT_ID () est facile à utiliser dans scripts pendant que mysql_insert_id () essaie de fournir plus exact informations sur ce qui arrive à la colonne AUTO_INCREMENT.

PHP mysqli_insert_id()

Exécution d'une instruction INSERT ou UPDATE à l'aide de LAST_INSERT_ID () fonction modifiera également la valeur renvoyée par mysqli_insert_id () une fonction.

Mettre tous ensemble:

$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 la classe DB est ici .)

9
Vladimir Kornea

Requête:

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

Fonction PHP:

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

C'est un travail pour moi;)

L'ID de la dernière ligne mise à jour est identique à celui que vous avez utilisé dans 'updateQuery' pour trouver et mettre à jour cette ligne. Alors, sauvegardez (appelez) cet ID comme vous le souhaitez.

last_insert_id() dépend du AUTO_INCREMENT, mais pas le dernier identifiant mis à jour. 

2
Driada

En savoir plus sur la réponse acceptée ci-dessus
Pour ceux qui s’interrogent sur := & =

Une différence significative entre := et =, à savoir que := fonctionne comme un opérateur d’affectation de variable partout, alors que = ne fonctionne de cette manière que dans les instructions SET et est un opérateur de comparaison partout ailleurs. 

Donc, SELECT @var = 1 + 1; laissera @var inchangé et renverra un boolean (1 ou 0 en fonction de la valeur actuelle de @var), alors que SELECT @var := 1 + 1; changera @var en 2 et retournera 2 . [La source]

2
Anon30

Hé, j'avais juste besoin d'un tel truc - je l'ai résolu d'une manière différente, peut-être que ça fonctionnera pour vous. Notez que ce n'est pas une solution évolutive et sera très mauvais pour les grands ensembles de données.

Divisez votre requête en deux parties - 

tout d'abord, sélectionnez les identifiants des lignes que vous souhaitez mettre à jour et stockez-les dans une table temporaire. 

deuxièmement, la mise à jour d'origine avec la condition de l'instruction de mise à jour modifiée en where id in temp_table.

Et pour assurer la concurrence, vous devez verrouiller la table avant ces deux étapes, puis relâcher le verrou à la fin.

Encore une fois, cela fonctionne pour moi, pour une requête qui se termine par limit 1, donc je n’utilise même pas une table temporaire, mais simplement une variable pour stocker le résultat de la première select

Je préfère cette méthode car je sais que je mettrai toujours à jour une seule ligne, et le code est simple. 

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

Je devais CASTER l'identifiant (je ne sais pas pourquoi) ... ou je ne pouvais pas obtenir le contenu @uids (c'était un blob) Merci beaucoup pour la réponse de Pomyk!

1
Gromish

Si vous ne faites que des insertions et que vous souhaitez en faire une de la même session, procédez comme indiqué dans la réponse de peirix. Si vous apportez des modifications, vous devrez modifier le schéma de votre base de données pour stocker l’entrée qui a été mise à jour le plus récemment.

Si vous voulez l'id de la dernière modification, qui provient peut-être d'une session différente (c'est-à-dire non celle qui vient d'être effectuée par le code PHP en cours d'exécution, mais celle qui a été effectuée en réponse à une requête différente), vous pouvez ajouter une colonne TIMESTAMP à votre table appelée last_modified (voir http://dev.mysql.com/doc/refman/5.1/en/datetime.html pour plus d'informations), puis définissez last_modified lors de la mise à jour = CURRENT_TIME.

Ceci fait, vous pouvez utiliser une requête du type: SELECT id FROM table ORDER BY last_modified DESC LIMIT 1; Pour obtenir la dernière ligne modifiée.

1
a1kmm

Ma solution est d’abord de choisir l’identifiant (@uids) avec la commande select et de mettre à jour cet identifiant avec @uids.

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

cela a fonctionné sur mon projet.

0
Ahmet Uğur