137 votes

insérer plusieurs lignes via un tableau php dans mysql

Je fais passer un grand ensemble de données dans une table mysql via php en utilisant des commandes d'insertion et je me demande s'il est possible d'insérer environ 1000 lignes à la fois via une requête autre que d'ajouter chaque valeur à la fin d'une longue chaîne de caractères et de l'exécuter ensuite. J'utilise le framework Codeigniter, donc ses fonctions sont également à ma disposition.

0 votes

J'ai donné la réponse à votre question sur l'insertion de rangs multiples de Codeigniter.

0 votes

@SomnathMuluk Merci, mais cela fait un moment que je n'ai pas eu à répondre à cette question :)...

0 votes

Je vous recommande d'utiliser la fonction insert_batch de CodeIgniter. Si vous utilisez une bibliothèque, essayez toujours de tirer parti de ses forces et de ses normes de codage.

241voto

staticsan Points 14435

Assemblage d'un INSERT avec plusieurs lignes est beaucoup plus rapide dans MySQL qu'une seule instruction INSERT par ligne.

Cela dit, il semble que vous rencontriez des problèmes de gestion des chaînes de caractères en PHP, ce qui est en fait un problème d'algorithme, et non de langage. Fondamentalement, lorsque vous travaillez avec de grandes chaînes de caractères, vous voulez minimiser les copies inutiles. Principalement, cela signifie que vous voulez éviter la concaténation. La manière la plus rapide et la plus efficace en termes de mémoire pour construire une grande chaîne de caractères, par exemple pour insérer des centaines de lignes en une seule fois, est de tirer profit de la fonction implode() et l'affectation de tableaux.

$sql = array(); 
foreach( $data as $row ) {
    $sql[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $sql));

L'avantage de cette approche est que vous n'avez pas à copier et recopier l'instruction SQL que vous avez assemblé jusqu'à présent avec chaque concaténation ; à la place, PHP fait ceci une fois dans le implode() déclaration. Il s'agit d'une grand gagner.

Si vous avez beaucoup de colonnes à assembler, et qu'une ou plusieurs d'entre elles sont très longues, vous pouvez également construire une boucle interne pour faire la même chose et utiliser la fonction implode() pour affecter la clause values au tableau externe.

5 votes

Merci pour cela ! En fait, il manque un crochet fermant à la fin de la fonction si quelqu'un a l'intention de la copier. mysql_real_query('INSERT INTO table VALUES (text, category) '.implode(','. $sql)) ;

3 votes

Merci ! Réparé. (Je fais souvent ça...)

0 votes

Je viens aussi de remarquer, moi qui suis bête, que l'implode(','. $sql)) ; devrait être implode(',', $sql)) ;

64voto

Somnath Muluk Points 10173

L'insertion multiple/insertion par lot est maintenant supportée par codeigniter. J'ai eu le même problème. Bien qu'il soit très tard pour répondre à la question, cela aidera quelqu'un. C'est pourquoi je réponds à cette question.

$data = array(
   array(
      'title' => 'My title' ,
      'name' => 'My Name' ,
      'date' => 'My date'
   ),
   array(
      'title' => 'Another title' ,
      'name' => 'Another Name' ,
      'date' => 'Another date'
   )
);

$this->db->insert_batch('mytable', $data);

// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date')

2 votes

Je pense que c'est la façon la plus recommandée de faire une insertion de plusieurs lignes plutôt que d'utiliser mysql_query. En effet, lorsque nous utilisons un framework, il est bon de toujours utiliser les fonctionnalités intégrées du framework.

22voto

Espresso_Boy Points 666

Vous pouvez préparer la requête pour insérer une ligne à l'aide de la classe mysqli_stmt, puis itérer sur le tableau de données. Quelque chose comme ça :

$stmt =  $db->stmt_init();
$stmt->prepare("INSERT INTO mytbl (fld1, fld2, fld3, fld4) VALUES(?, ?, ?, ?)");
foreach($myarray as $row)
{
    $stmt->bind_param('idsb', $row['fld1'], $row['fld2'], $row['fld3'], $row['fld4']);
    $stmt->execute();
}
$stmt->close();

Où 'idsb' sont les types de données que vous liez (int, double, string, blob).

7 votes

J'ai récemment effectué des tests comparatifs entre l'insertion en masse et l'insertion préparée, comme indiqué ici. Pour environ 500 insertions, la méthode des insertions préparées s'est terminée entre 2,6 et 4,4 secondes, et la méthode des insertions en vrac entre 0,12 et 0,35 secondes. J'aurais pensé que mysql aurait "regroupé" ces instructions préparées et les aurait exécutées aussi bien que les insertions en masse, mais dans une configuration par défaut, la différence de performance est apparemment énorme. (Toutes les requêtes comparées ont été exécutées à l'intérieur d'une seule transaction pour chaque test, afin d'éviter l'auto-committing)

15voto

Ross Carver Points 71

Je sais qu'il s'agit d'une vieille requête, mais j'étais en train de lire et j'ai pensé ajouter ce que j'ai trouvé ailleurs :

mysqli en PHP 5 est un ojbjet avec quelques bonnes fonctions qui vous permettront d'accélérer le temps d'insertion pour la réponse ci-dessus :

$mysqli->autocommit(FALSE);
$mysqli->multi_query($sqlCombined);
$mysqli->autocommit(TRUE);

Désactiver autocommit lors de l'insertion de nombreuses lignes accélère considérablement l'insertion, donc désactivez-le, puis exécutez comme indiqué ci-dessus, ou créez simplement une chaîne (sqlCombined) qui est constituée de plusieurs instructions d'insertion séparées par des points-virgules et multi-query les traitera correctement.

J'espère que cela aidera quelqu'un à gagner du temps (recherche et insertion !).

R

0 votes

Voici l'erreur que j'ai obtenue en utilisant votre idée : "Fatal error : Call to a member function autocommit() on null in /homepages/25/d402746174/htdocs/MoneyMachine/saveQuotes.php on line 30"

8voto

vezult Points 3812

Vous pouvez toujours utiliser la fonction de mysql LOAD DATA :

LOAD DATA LOCAL INFILE '/full/path/to/file/foo.csv' INTO TABLE `footable` FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n'

pour effectuer des insertions en vrac plutôt que d'utiliser un ensemble de INSERT déclarations.

0 votes

Je l'avais envisagé, mais je dois manipuler les données avant de les insérer. Elles m'ont été données sous la forme d'un produit cartésien d'un ensemble de 1400 par 1400 de valeurs int dont beaucoup sont nulles. J'ai besoin de convertir cela en une relation de plusieurs à plusieurs en utilisant une table intermédiaire pour économiser de l'espace, d'où le besoin d'insertions par opposition à une insertion en masse.

0 votes

Vous pouvez toujours générer un fichier csv après l'avoir manipulé et avoir appelé l'instruction mysql qui charge les données.

0 votes

Je pense qu'il est utile de savoir que le chemin est local à votre client SQL, et non sur le serveur SQL. Le fichier est téléchargé sur le serveur et ensuite lu par celui-ci. Je pensais que le fichier devait déjà être sur le serveur, ce qui n'est pas le cas. S'il est déjà sur le serveur, supprimez l'élément LOCAL bit.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X