Ответ 1
Используя технику вашей второй идеи, вы можете сгенерировать запрос, перейдя по массиву и используя:
$this->db->query($query_string);
Я пытаюсь вставить несколько строк в таблицу MySQL, используя Codeigniter и Active Records.
Код PHP
$data = array('......'); // some rows of data to insert
$this->db->insert_batch('my_table', $data);
Однако это может привести к тому, что в таблицу будут вставлены повторяющиеся строки. Чтобы обработать вставку дублированных данных, я планирую использовать команду INSERT IGNORE
, чтобы не вставлять строку, если строка является дубликатом.
Проблема: Я не могу найти эквивалент INSERT IGNORE
в Active Records и не хочу редактировать класс Active Record. Существуют ли другие альтернативы?
Следующее выглядит интересным, но если я сделаю следующее, не будет ли запрос дважды выполняться?
$insert_query = $this->db->insert_batch('my_table', $data); // QUERY RUNS ONCE
$insert_query = str_replace('INSERT INTO','INSERT IGNORE INTO',$insert_query);
$this->db->query($insert_query); // QUERY RUNS A SECOND TIME
Используя технику вашей второй идеи, вы можете сгенерировать запрос, перейдя по массиву и используя:
$this->db->query($query_string);
Не используйте insert_batch
, поскольку он действительно запускает запрос. Вы хотите insert_string
$insert_query = $this->db->insert_string('my_table', $data);
$insert_query = str_replace('INSERT INTO','INSERT IGNORE INTO',$insert_query);
$this->db->query($insert_query);
UPDATE. Это не работает для пакетных запросов, только по одной строке за раз.
Для пакетных загрузок вам может понадобиться нечто большее:
foreach ($data as $data_item) {
$insert_query = $this->db->insert_string('my_table', $data_item);
$insert_query = str_replace('INSERT INTO', 'INSERT IGNORE INTO', $insert_query);
$this->db->query($insert_query);
}
ОБНОВЛЕНИЕ: Используйте версию dcostalis (в комментариях ниже этого), она будет масштабироваться намного лучше: -)
Поскольку я также столкнулся с подобной проблемой, я, наконец, выбрал немного более "элегантное" решение, подобное приведенному ниже. Полный запрос insert_batch, который использует ответ Rocket и транзакции:
$this->db->trans_start();
foreach ($items as $item) {
$insert_query = $this->db->insert_string('table_name', $item);
$insert_query = str_replace('INSERT INTO', 'INSERT IGNORE INTO', $insert_query);
$this->db->query($insert_query);
}
$this->db->trans_complete();
Это также обернет все транзакции, в результате чего будет выполняться более быстрый запрос, например, с помощью insert_batch(). Ну не так быстро, как insert_batch(), но быстрее, чем один запрос для каждой записи курса. Надеюсь, это поможет кому-то.
Только что нашел это, может помочь http://www.amplio.ch/blog/web-development/codeigniter-active-record-class-and-insert-ignore/, это ci hack хотя
Не рекомендуется, но вот взломать пакетную вставку (что более эффективно для Mysql)
// try to insert as usual first
$this->db->insert_batch('my_table', $data);
// if it fails resort to IGNORE
if($this->db->_error_message())
{
$sql = $this->db->last_query();
$sql = str_replace('INSERT INTO', 'INSERT IGNORE INTO', $sql);
$this->db->query($sql);
}
С этой целью я сделал эту вспомогательную функцию:
function insert_batch_string($table='',$data=[],$ignore=false){
$CI = &get_instance();
$sql = '';
if ($table && !empty($data)){
$rows = [];
foreach ($data as $row) {
$insert_string = $CI->db->insert_string($table,$row);
if(empty($rows) && $sql ==''){
$sql = substr($insert_string,0,stripos($insert_string,'VALUES'));
}
$rows[] = trim(substr($insert_string,stripos($insert_string,'VALUES')+6));
}
$sql.=' VALUES '.implode(',',$rows);
if ($ignore) $sql = str_ireplace('INSERT INTO', 'INSERT IGNORE INTO', $sql);
}
return $sql;
}
Он может вставлять пакетную вставку и пакетную вставку с игнорированием. Чтобы избежать дублирования строк, вы должны установить уникальный ключ в таблице базы данных для первичного поля.
Это в основном модификация предложения Rocket Hazmat, что отлично, но не учитывает тот факт, что str_replace работает со всей строкой и может непреднамеренно повлиять на данные.
$insert_query = $this->db->insert_string('my_table', $data);
$insert_query = preg_replace('/INSERT INTO/','INSERT IGNORE INTO',$insert_query,1);
$this->db->query($insert_query);
добавить в файл DB_query_builder.php
эти 2 функции
public function insert_ignore_batch($table = '', $set = NULL, $escape = NULL) {
if ($set !== NULL)
{
$this->set_insert_batch($set, '', $escape);
}
if (count($this->qb_set) === 0)
{
// No valid data array. Folds in cases where keys and values did not match up
return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
}
if ($table === '')
{
if ( ! isset($this->qb_from[0]))
{
return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
}
$table = $this->qb_from[0];
}
// Batch this baby
$affected_rows = 0;
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
{
$this->query($this->_insert_ignore_batch($this->protect_identifiers($table, TRUE, $escape, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, 100)));
$affected_rows += $this->affected_rows();
}
$this->_reset_write();
return $affected_rows;
}
protected function _insert_ignore_batch($table, $keys, $values) {
return 'INSERT IGNORE INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
}
с помощью:
$this->db->insert_ignore_batch('TableName', $data);
Избегайте дублирования строк, установив уникальный ключ в таблице базы данных по крайней мере для одного из полей.
У меня тоже была такая же проблема, что помогло мне:
Открыть: Codeigniter/system/database/DB_query_builder.php:
найдите
protected function _insert_batch($table, $keys, $values)
{
return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
}
и замените на:
protected function _insert_batch($table, $keys, $values)
{
return 'INSERT IGNORE INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
}