Php 使用Codeigniter插入忽略

Php 使用Codeigniter插入忽略,php,codeigniter,activerecord,Php,Codeigniter,Activerecord,我试图使用Codeigniter和活动记录在MySQL表中插入几行 PHP代码 $data = array('......'); // some rows of data to insert $this->db->insert_batch('my_table', $data); 但是,这可能会导致在表中插入重复的行。为了处理重复数据的插入,我计划使用INSERT IGNORE命令,如果行是重复的,则不插入该行 问题:我在活动记录中找不到等效的INSERT IGNORE,不想编辑活

我试图使用Codeigniter和活动记录在MySQL表中插入几行

PHP代码

$data = array('......');  // some rows of data to insert
$this->db->insert_batch('my_table', $data);
但是,这可能会导致在表中插入重复的行。为了处理重复数据的插入,我计划使用
INSERT IGNORE
命令,如果行是重复的,则不插入该行

问题:我在活动记录中找不到等效的
INSERT IGNORE
,不想编辑活动记录类。还有其他选择吗

下面的内容看起来很有趣,但是如果我执行下面的操作,查询不会运行两次吗

$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\u batch
,因为它实际上运行查询。你想要


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

对于批处理上载,您可能需要以下内容:

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的版本(在下面的评论中),它的伸缩性会更好:-)

由于我也遇到了类似的问题,我最终选择了一个更“优雅”的解决方案,如下所示。使用Rocket的答案和事务的完整insert_批处理查询:

$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()快,但比每个条目的单个查询快。我希望它能帮助一些人。

不推荐使用,但这里有一个保留批插入的方法(wrt Mysql更有效)


为此,我创建了以下帮助器函数:

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

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

打开:Codeigniter/system/database/DB\u query\u builder.php

发现

并替换为:

protected function _insert_batch($table, $keys, $values)
{
    return 'INSERT IGNORE INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
}

添加到文件DB_query_builder.php

这两个功能

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);
}
解决方案:

$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:)

如果仍有人在努力使用insert_batch来忽略

检查此路径

system/database/DB_query_builder.php
搜索函数

protected function _insert_batch
改变

INSERT INTO => INSERT IGNORE INTO

以后谢谢我。:)

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

在尝试插入重复行时,这会导致错误发生吗?如果将“debug”的database.php config变量设置为false,则不会发生错误。错误仍然会生成,codeigniter会忽略它;这不是一个很好的解决方案我用它作为问题的快速解决方案(我只插入了一个小数组),不确定它在一个大数组中的伸缩性如何。
$sql=“”;foreach($data as$data_item){$insert_query=$this->db->insert_string('my_table',$data_item);$sql.=str_replace('insert INTO','insert IGNORE INTO',$insert_query);}$this->db->query($sql)如果您仍然只想运行一个SQL命令来执行批插入,可以使用以下代码<代码>$batch\u assignment=$this->db->set\u insert\u batch($batch\u assignment);$query=$this->db->\u insert\u batch('users\u to\u tasks',array('task\u id','user\u id'),$this->db->ar\u set)在阅读了所有的答案后,让我总结一下-作为一个批处理没有很好的方法
:(
我用MySQL 5.5.42尝试了INSERT IGNORE,并且有效。但是有一个副作用,即即使没有插入任何内容,自动增量也会继续增加。我使用ajax,但仍然会出现重复错误..:(我不想出现重复错误,只要移动到insert ignore(如果存在重复)。浏览器上发生的事情不会影响mysql的行为。你尝试过我建议的方法吗?如果你想消除数据库错误,请调整数据库配置设置。如果你处理了错误,insert应该通过。这会起作用,但不是一个很好的解决方案。一旦出现您不记得要执行的CI更新,您就产生了一个问题。。这会导致忽略其他不需要重复的错误吗?您还需要在mysql配置文件中添加这一行
innodb_autoinc_lock_mode=0
,以防止即使在ig上自动递增计数器也会递增nored条目。谢谢@Hazmat。对于那些想知道是插入还是忽略的人,可以使用“$this->db->insert_id();”并检查它是否大于零。它可能会起作用,但更改系统文件不是很酷。一个非常难看的解决方案是;)
$sql = $this->db->set($data)->get_compiled_insert($table);
$sql = str_replace('INSERT INTO', 'INSERT IGNORE INTO', $sql);
$this->db->query($sql);
system/database/DB_query_builder.php
protected function _insert_batch
INSERT INTO => INSERT IGNORE INTO