Подтвердить что ты не робот

INSERT IGNORE с использованием Codeigniter

Я пытаюсь вставить несколько строк в таблицу 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
4b9b3361

Ответ 1

Используя технику вашей второй идеи, вы можете сгенерировать запрос, перейдя по массиву и используя:

$this->db->query($query_string);

Ответ 2

Не используйте 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. Это не работает для пакетных запросов, только по одной строке за раз.

Ответ 3

Для пакетных загрузок вам может понадобиться нечто большее:

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 (в комментариях ниже этого), она будет масштабироваться намного лучше: -)

Ответ 4

Поскольку я также столкнулся с подобной проблемой, я, наконец, выбрал немного более "элегантное" решение, подобное приведенному ниже. Полный запрос 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(), но быстрее, чем один запрос для каждой записи курса. Надеюсь, это поможет кому-то.

Ответ 6

Не рекомендуется, но вот взломать пакетную вставку (что более эффективно для 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);
}

Ответ 7

С этой целью я сделал эту вспомогательную функцию:

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

Он может вставлять пакетную вставку и пакетную вставку с игнорированием. Чтобы избежать дублирования строк, вы должны установить уникальный ключ в таблице базы данных для первичного поля.

Ответ 8

Это в основном модификация предложения 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);

Ответ 9

добавить в файл 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);

Ответ 10

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

Ответ 11

У меня тоже была такая же проблема, что помогло мне:

Открыть: 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);
}