Как я могу сохранить массивы значений в базе данных?

8

Я пытаюсь сохранить несколько значений из текстовой области в таблицу базы данных.

Я использую следующий код, но я чувствую, что это неправильный путь.

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

Есть ли другой способ достижения того же результата?

Мохамед Ибрагим
источник

Ответы:

15

Я бы использовал следующий код.

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

В качестве альтернативы вы можете использовать следующий код.

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

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

$query->execute();

В MySQL запрос использует многозначный синтаксис.

В других базах данных выполненные запросы будут по одному на каждый вызов $query->values(), заключенные в транзакцию. Это означает, что запросы будут откатываться при сбое одного из них. Фактически, код, выполняемый из InsertQuery :: execute (), является следующим.

  // 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;
  }

Короче говоря, я бы использовал код, который вы используете, если вставленные значения не зависят друг от друга; Я бы использовал код, который я показал, когда значения зависят друг от друга.

В вашем случае электронные письма независимы друг от друга. Если бы вы использовали второй фрагмент, который я показал, таблица базы данных будет содержать все значения, когда подзапрос не завершится неудачей, или ни одного, если один подзапрос завершится неудачно.

Вы также можете использовать drupal_write_record(), хотя я предпочитаю другие фрагменты.

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

Я не вижу ни одного профессионала в использовании этого фрагмента.

Ссылка

киамлалуно
источник
1
Извините, что насчет "Multi-Insert Form", показанной на этой странице документации. Дайте 1 массив $valuesи только вызовите 1 execute(). drupal.org/node/310079 Это используется, например, при создании блоков стандартных профилей по умолчанию.
Tenken
2
«Это верно, вы можете позвонить ->values(...)столько раз , сколько вы хотите на условиях InsertQueryи подготовит запрос типаINSERT INTO x (field1, field2) VALUES ('val1', 'val2'), ('val3', 'val4'), etc
Clive
2
Хорошо, теперь я вспомнил, почему я отказался от использования $query->values(): в большинстве случаев значения, которые вставляет мой код, не зависят друг от друга, и я не хочу, чтобы ошибка со значением вызывала откат других значений.
kiamlaluno
3

Эта версия похожа на ваш код, но имеет лучшую производительность. Вы действительно не хотите вызывать execute () тысячу раз, вам нужно вызвать его только один раз.

Ссылка

$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
источник
Работал для меня, за исключением того, что он выдавал бы ошибки OOM, когда число строк слишком велико (10 000) в моем случае. Поэтому я разделил это на партии по 1000 или меньше, чтобы решить эту проблему.
Эдуардо Чонгкан