web-dev-qa-db-fra.com

MySQL LAST_INSERT_ID () utilisé avec plusieurs instructions INSERT

Si j'insère plusieurs enregistrements avec une boucle qui exécute une seule insertion d'enregistrement, le dernier identifiant d'insertion renvoyé est, comme prévu, le dernier. Mais si je fais une instruction d'insertion de plusieurs enregistrements:

INSERT INTO people (name,age)
VALUES ('William',25), ('Bart',15), ('Mary',12);

Disons que les trois ci-dessus sont les premiers enregistrements insérés dans le tableau. Après l'instruction d'insertion, je m'attendais à ce que le dernier identifiant d'insertion renvoie 3, mais il a renvoyé 1. Le premier identifiant d'insertion de l'instruction en question.

Quelqu'un peut-il donc confirmer s'il s'agit du comportement normal de LAST_INSERT_ID() dans le contexte d'instructions INSERT à enregistrements multiples. Je peux donc baser mon code dessus.

39
bogdan

Oui. Ce comportement de last_insert_id() est documenté dans la documentation MySQL :

Important
Si vous insérez plusieurs lignes à l'aide d'une seule instruction INSERT , LAST_INSERT_ID() renvoie la valeur générée pour la première insérée ligne uniquement. La raison en est de permettre de reproduire facilement la même instruction INSERT sur un autre serveur.

41
Asaph

Ce comportement est mentionné sur la page de manuel pour MySQL. C'est dans les commentaires mais n'est pas contesté, donc je suppose que c'est le comportement attendu.

2
Larry Lustig

Je pense que c'est possible si votre table a une colonne (ID) d'auto-incrémentation unique et que vous n'avez pas besoin qu'elles soient retournées par mysql lui-même. Je vous coûterais 3 demandes de base de données supplémentaires et un certain traitement. Cela nécessiterait ces étapes:

  1. Obtenez "Avant MAX (ID)" juste avant votre encart:
    SELECT MAX(id) AS before_max_id FROM table_name`
  1. Effectuez plusieurs requêtes INSERT ... VALUES () avec vos données et conservez-les:

    INSERT INTO table_name
    (col1, col2)
    VALUES 
    ("value1-1" , "value1-2"), 
    ("value2-1" , "value2-2"), 
    ("value3-1" , "value3-2"), 
    ON DUPLICATE KEY UPDATE
    
  2. Obtenez "After MAX (ID)" juste après votre insertion:

    SELECT MAX(id) AS after_max_id FROM table_name`
    
  3. Obtenez des enregistrements avec des ID entre "Avant MAX (ID)" et "Après MAX (ID)", notamment:

    SELECT * FROM table_name WHERE id>$before_max_id AND id<=$after_max_id`
    
  4. Vérifiez les données récupérées avec les données que vous avez insérées pour les faire correspondre et supprimez tous les enregistrements que vous n'avez pas insérés. Les enregistrements restants ont vos identifiants:

    foreach ($after_collection as $after_item) {
      foreach ($input_collection as $input_item) {
        if ( $after_item->compare_content($input_item) ) {
          $intersection_array[] = $after_item;
        }
      }
    }

C'est comme ça qu'une personne ordinaire le résoudrait dans un monde réel, avec des parties de code. Grâce à l'auto-incrémentation, il devrait obtenir le plus petit nombre possible d'enregistrements à vérifier, de sorte qu'ils ne prendront pas beaucoup de traitement. Ce n'est pas le code "copier-coller" final - par exemple. vous devez créer votre propre fonction compare_content () selon vos besoins.

1
Marcel Zúbrik