web-dev-qa-db-fra.com

MySQL ON DUPLICATE KEY - dernier insert id?

J'ai la requête suivante:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE a=1

Je veux l'ID de l'insertion ou de la mise à jour. Habituellement, je lance une seconde requête afin d'obtenir ceci, car je pense que insert_id () ne renvoie que l'ID 'inséré' et non l'ID mis à jour.

Est-il possible d'insérer/mettre à jour et de récupérer l'ID de la ligne sans exécuter deux requêtes?

120
thekevinscott

Consultez cette page: https://web.archive.org/web/20150329004325/https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html =
Au bas de la page, ils expliquent comment rendre LAST_INSERT_ID significatif pour les mises à jour en transmettant une expression à cette fonction MySQL.

À partir de l'exemple de documentation MySQL:

Si une table contient une colonne AUTO_INCREMENT et que INSERT ... UPDATE insère une ligne, la fonction LAST_INSERT_ID () renvoie la valeur AUTO_INCREMENT. Si l'instruction met à jour une ligne, LAST_INSERT_ID () n'a pas de sens. Toutefois, vous pouvez contourner ce problème en utilisant LAST_INSERT_ID (expr). Supposons que cet identifiant soit la colonne AUTO_INCREMENT. Pour que LAST_INSERT_ID () ait du sens pour les mises à jour, insérez les lignes comme suit:

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;
156
fredrik

Pour être exact, s'il s'agit de la requête d'origine:

INSERT INTO table (a) VALUES (0)
 ON DUPLICATE KEY UPDATE a=1

et 'id' est la clé primaire à incrémentation automatique, ce qui constituerait la solution de travail:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1

Est-ce que tout est ici: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Si une table contient une colonne AUTO_INCREMENT et que INSERT ... UPDATE insère une ligne, la fonction LAST_INSERT_ID () renvoie la valeur AUTO_INCREMENT. Si l'instruction met à jour une ligne, LAST_INSERT_ID () n'a pas de sens. Toutefois, vous pouvez contourner ce problème en utilisant LAST_INSERT_ID (expr). Supposons que cet identifiant soit la colonne AUTO_INCREMENT.

32
Aleksandar Popovic

Vous pouvez examiner REPLACE, qui consiste essentiellement en une suppression/insertion si l'enregistrement existe. Mais cela changerait le champ d'incrémentation automatique s'il était présent, ce qui pourrait rompre les relations avec d'autres données.

2
Brent Baisley

Je ne sais pas quelle est votre version de MySQL mais avec InnoDB, il y avait un bug avec autoinc

bug dans 5.1.20 et corrigé dans 5.1.23 http://bugs.mysql.com/bug.php?id=27405

bug dans 5.1.31 et corrigé dans 5.1.33 http://bugs.mysql.com/bug.php?id=42714

2

Les solutions existantes fonctionnent si vous utilisez l'auto-incrémentation. J'ai une situation où l'utilisateur peut définir un préfixe et il devrait recommencer la séquence à 3 000. En raison de ce préfixe varié, je ne peux pas utiliser l'auto-incrémentation, ce qui rend last_insert_id vide pour les insertions. Je l'ai résolu avec ce qui suit:

INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1);
SELECT LAST_INSERT_ID();

Si le préfixe existe, il sera incrémenté et peuplera last_insert_id. Si le préfixe n'existe pas, il l'insérera avec la valeur 3000 et remplira last_insert_id avec 3000.

0
Aaron

Il convient de noter, et cela peut être évident (mais je le dis quand même pour plus de clarté ici), que REPLACE supprimera la ligne correspondante existante avant d'insérer vos nouvelles données. ON DUPLICATE KEY UPDATE met à jour uniquement les colonnes spécifiées et conserve la ligne.

Du manuel :

REPLACE fonctionne exactement comme INSERT, sauf que si une ancienne ligne de la table a la même valeur qu'une nouvelle ligne pour une clé PRIMARY KEY ou un index UNIQUE, l'ancienne ligne est supprimée avant que la nouvelle ligne ne soit insérée.

0
Greg K