web-dev-qa-db-fra.com

Comment puis-je insérer de nombreuses lignes dans une table MySQL et renvoyer les nouveaux ID?

Normalement, je peux insérer une ligne dans une table MySQL et obtenir le last_insert_id retour. Maintenant, cependant, je veux insérer en vrac de nombreuses lignes dans la table et récupérer un tableau d'ID. Est-ce que quelqu'un sait comment je peux faire ça?

Il y a des questions similaires, mais elles ne sont pas exactement les mêmes. Je ne veux pas insérer le nouvel ID dans une table temporaire; Je veux juste récupérer le tableau des identifiants.

Puis-je récupérer le lastInsertId d'une insertion en bloc?

instruction d'insertion-sélection de lignes multiples Mysql avec last_insert_id ()

67
Peacemoon

Ancien thread mais juste examiné, alors voici: si vous utilisez InnoDB sur une version récente de MySQL, vous pouvez obtenir la liste des ID en utilisant LAST_INSERT_ID() et ROW_COUNT().

InnoDB garantit des nombres séquentiels pour AUTO INCREMENT lors de l'insertion en bloc, à condition que innodb_autoinc_lock_mode Soit réglé sur 0 (traditionnel) ou 1 (consécutif). Par conséquent, vous pouvez obtenir l'ID premier de LAST_INSERT_ID() et dernier en ajoutant ROW_COUNT()-1.

63

La seule façon dont je peux penser que cela pourrait être fait est que si vous stockez un identifiant unique pour chaque ensemble de lignes insérées (guid), puis sélectionnez les identifiants de ligne. par exemple:

INSERT INTO t1
(SELECT col1,col2,col3,'3aee88e2-a981-1027-a396-84f02afe7c70' FROM a_very_large_table);
COMMIT;

SELECT id FROM t1 
WHERE guid='3aee88e2-a981-1027-a396-84f02afe7c70';

Vous pouvez également générer le guid dans la base de données en utilisant uuid()

13
Kevin Burton

Supposons que nous ayons une table appelée tentable avec deux colonnes uid, col1 où uid est un champ d'incrémentation automatique. Faire quelque chose comme ci-dessous renverra tous les identifiants insérés dans le jeu de résultats. Vous pouvez parcourir le jeu de résultats et obtenir vos identifiants. Je me rends compte qu'il s'agit d'un ancien poste et que cette solution pourrait ne pas fonctionner dans tous les cas. Mais pour d'autres, c'est possible et c'est pourquoi j'y réponds.

# lock the table
lock tables temptable write;

#bulk insert the rows;
insert into temptable(col1) values(1),(2),(3),(4);

#get the value of first inserted row. when bulk inserting last_insert_id() #should give the value of first inserted row from bulk op.
set @first_id = last_insert_id();

#now select the auto increment field whose value is greater than equal to #the first row. Remember since you have write lock on that table other #sessions can't write to it. This resultset should have all the inserted #id's
select uid from temptable where uid >=@first_id;

#now that you are done don't forget to unlock the table.
unlock tables;
4
sundeep

Je pense que vous devrez soit gérer l'ID de transaction dans votre application, soit l'ID d'article dans votre application afin de le faire parfaitement.

Une façon de faire cela qui pourrait fonctionner, en supposant que toutes vos insertions réussissent (!), Est la suivante:

Vous pouvez ensuite obtenir les identifiants insérés avec une boucle pour le nombre de lignes affectées, en commençant par lastid (qui est le premier identifiant inséré de l'insertion en bloc). Et donc, j'ai vérifié que cela fonctionne parfaitement .. faites juste attention à ce que HeidiSQL par exemple ne retourne pas la valeur correcte pour ROW_COUNT (), probablement parce que c'est une interface graphique merdique faisant de la merde aléatoire, nous ne le demandons pas - cependant c'est parfaitement correct de l'un ou l'autre ligne de commande ou PHP mysqli -

START TRANSACTION;
BEGIN;
INSERT into test (b) VALUES ('1'),('2'),('3');
SELECT LAST_INSERT_ID() AS lastid,ROW_COUNT() AS rowcount;
COMMIT;

Dans PHP cela ressemble à ceci (local_sqle est un appel direct à mysqli_query, local_sqlec est un appel à mysqli_query + convert resultset to PHP array):

local_sqle("START TRANSACTION;
BEGIN;
INSERT into test (b) VALUES ('1'),('2'),('3');");
$r=local_sqlec("SELECT LAST_INSERT_ID() AS lastid,ROW_COUNT() AS rowcount;");
local_sqle("
COMMIT;");
$i=0;
echo "last id =".($r[0]['lastid'])."<br>";
echo "Row count =".($r[0]['rowcount'])."<br>";

while($i<$r[0]['rowcount']){
    echo "inserted id =".($r[0]['lastid']+$i)."<br>";
    $i++;
}

La raison pour laquelle les requêtes sont séparées est que je n'obtiendrais pas autrement mon résultat en utilisant mes propres fonctions.Si vous le faites avec des fonctions standard, vous pouvez le replacer dans une instruction, puis récupérer le résultat dont vous avez besoin (il doit s'agir du numéro de résultat 2 - en supposant que vous utilisez une extension qui gère plus d'un jeu de résultats/requête).

0
Morg.