Comment puis-je enregistrer des tableaux de valeurs dans la base de données?

8

J'essaie d'enregistrer plusieurs valeurs d'une zone de texte dans une table de base de données.

J'utilise le code suivant, mais je pense que c'est la mauvaise façon.

foreach ($user_emails as $key => $value) {
  $insert_banned_emails = db_insert('banned_users');
  $insert_banned_emails
    ->fields(array(
      'email' => $value,
    ))
    ->execute();
}

Existe-t-il une manière différente d'obtenir le même résultat?

Mohamed Ibrahim
la source

Réponses:

15

J'utiliserais le code suivant.

foreach ($user_emails as $value) {
  $query = db_insert('banned_users');
  $query->fields(array('email' => $value))->execute();
}

Vous pouvez également utiliser le code suivant.

$query = db_insert('banned_users')->fields(array('email'));

foreach ($user_emails as $value) {
  $query->values(array('email' => $value));
}

$query->execute();

Avec MySQL, la requête utilise la syntaxe à valeurs multiples.

Avec d'autres bases de données, les requêtes exécutées seront une pour chaque appel à $query->values(), encapsulées dans une transaction. Cela signifie que les requêtes seront annulées en cas d'échec de l'une d'entre elles. En fait, le code exécuté à partir de InsertQuery :: execute () est le suivant.

  // Each insert happens in its own query in the degenerate case. However,
  // we wrap it in a transaction so that it is atomic where possible. On many
  // databases, such as SQLite, this is also a notable performance boost.
  $transaction = $this->connection->startTransaction();

  try {
    $sql = (string) $this;
    foreach ($this->insertValues as $insert_values) {
      $last_insert_id = $this->connection->query($sql, $insert_values, $this->queryOptions);
    }
  }
  catch (Exception $e) {
    // One of the INSERTs failed, rollback the whole batch.
    $transaction->rollback();
    // Rethrow the exception for the calling code.
    throw $e;
  }

En bref, j'utiliserais le code que vous utilisez si les valeurs insérées sont indépendantes les unes des autres; J'utiliserais le code que j'ai montré lorsque les valeurs dépendent les unes des autres.

Dans votre cas, les e-mails sont indépendants les uns des autres. Si vous utilisiez le deuxième extrait que j'ai montré, la table de base de données contiendra toutes les valeurs, lorsque la sous-requête n'échouera pas, ou aucune lorsqu'une seule sous-requête échouera.

Vous pouvez également utiliser drupal_write_record(), même si je préfère de loin les autres extraits.

foreach ($user_emails as $value) {
  drupal_write_record('banned_users', array('email' => $value));
}

Cependant, je ne vois aucun pro dans l'utilisation de cet extrait.

Référence

kiamlaluno
la source
1
Je suis désolé pour le "formulaire d'insertion multiple" affiché sur cette page de documentation. Donnez 1 tableau de $valueset appelez seulement 1 execute(). drupal.org/node/310079 Ceci est utilisé par exemple dans la création de blocs par défaut des profils standard.
tenken
2
C'est vrai, vous pouvez appeler ->values(...)autant de fois que vous le souhaitez sur un InsertQueryet cela préparera une requête commeINSERT INTO x (field1, field2) VALUES ('val1', 'val2'), ('val3', 'val4'), etc
Clive
2
Bon, maintenant je me souviens pourquoi j'ai abandonné l'utilisation $query->values(): dans la plupart de mes cas, les valeurs que mon code insère sont indépendantes les unes des autres, et je ne veux pas qu'une erreur avec une valeur provoque une restauration des autres valeurs.
kiamlaluno
3

Il s'agit d'une version similaire à votre code, mais de meilleures performances. Vous ne voulez vraiment pas appeler execute () mille fois, vous n'avez besoin de l'appeler qu'une seule fois.

Référence

$insert_banned_emails = db_insert('banned_users')->fields(array('email'));
foreach ($user_emails as $key => $value) {
  $insert_banned_emails->values(array(
    'email' => $value,
  ));               
}
$insert_banned_emails->execute();
donutdan4114
la source
A fonctionné pour moi, sauf qu'il déclencherait des erreurs MOO lorsque le nombre de lignes est trop grand (10 000) dans mon cas. J'ai donc divisé cela en lots de 1 000 ou moins pour résoudre ce problème.
Eduardo Chongkan