26

我正在尝试使用 Codeigniter 和 Active Records 在 MySQL 表中插入几行。

PHP 代码

$data = array('......');  // some rows of data to insert
$this->db->insert_batch('my_table', $data);

但是,这可能会导致重复的行被插入到表中。INSERT IGNORE为了处理重复数据的插入,如果行是重复的,我计划使用命令不插入行。

问题:我在 Active Records 中找不到INSERT IGNORE等效项,并且不想编辑 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
4

13 回答 13

44

不要使用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);

更新:这不适用于批量查询,一次只能一行。

于 2012-06-10T04:01:43.177 回答
8

由于我也遇到了类似的问题,所以我最终选择了像下面这样一个更“优雅”的解决方案。一个完整的 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() 快,但比每个条目的单个查询快。我希望它会帮助某人。

于 2013-12-02T08:35:58.870 回答
7

对于批量上传,您可能需要更多类似的东西:

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 的版​​本(在下面的评论中),它会扩展得更好:-)

于 2013-01-10T14:44:00.977 回答
4

这基本上是对 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);
于 2015-10-13T18:58:49.090 回答
3

使用第二个想法的技术,您可以通过遍历数组并使用以下方法生成查询:

$this->db->query($query_string);
于 2012-06-10T02:16:43.343 回答
1

为此,我制作了这个辅助函数:

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

它可以进行批量插入和批量插入忽略。为避免重复行,您必须在数据库表中为主字段设置唯一键。

于 2015-06-03T16:05:24.137 回答
1

解决方案 :

$sql = $this->db->set($data)->get_compiled_insert($table);
$sql = str_replace('INSERT INTO', 'INSERT IGNORE INTO', $sql);
$this->db->query($sql);

适用于 codeigniter 3.0.6 :)

于 2018-05-11T20:25:42.587 回答
1

如果仍然有人在为 insert_batch 使用忽略而苦苦挣扎,

检查这条路径,

system/database/DB_query_builder.php

搜索功能

protected function _insert_batch

改变

INSERT INTO => INSERT IGNORE INTO

晚点再谢我。:)

于 2019-02-21T11:10:23.087 回答
0

不强烈推荐,但这里有一个保留批量插入的技巧(这在 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);
}
于 2014-07-10T05:57:47.473 回答
0

添加到文件 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);
于 2015-11-17T14:17:04.620 回答
0

我也有同样的问题帮助我的是:

打开: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);
}
于 2015-10-28T18:45:49.680 回答
0

避免在 codeigniter 中插入重复数据是一项棘手的任务。但是您可以使用自定义库方法以非常简单和准确的方式忽略重复值插入。我在以下位置找到了合适的解决方案: how-to-avoid-duplicate-data-insertion-in-codeigniter-php

于 2020-01-08T08:58:13.550 回答
-1

通过在数据库表中为至少一个字段设置唯一键来避免重复行。

于 2012-06-10T02:10:03.690 回答