我正在尝试使用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
答案 0 :(得分:38)
不要使用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);
更新:这不适用于批量查询,一次只能运行一行。
答案 1 :(得分:8)
由于我也遇到了类似的问题,我最终选择了一点点"优雅"解决方案如下所示。一个完整的insert_batch查询,它使用Rocket的答案AND事务:
$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()快,但比每个条目的单个查询更快。我希望它会帮助别人。
答案 2 :(得分: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的版本(在下面的评论中),它会扩展得更好: - )
答案 3 :(得分:3)
使用您的第二个想法的技术,您可以通过循环数组并使用:
生成查询$this->db->query($query_string);
答案 4 :(得分:3)
这基本上是对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);
答案 5 :(得分:0)
不是强烈推荐但是这里有一个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);
}
答案 6 :(得分:0)
为此我做了这个辅助功能:
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;
}
它可以使用ignore进行批量插入和批量插入。 要避免重复行,必须在主数据库的数据库表中设置唯一键。
答案 7 :(得分: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);
}
答案 8 :(得分:0)
添加到文件DB_query_builder.php
这2个功能
COMPUTE newvar= any(1,var1,var2,var3).
使用:
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);
}
答案 9 :(得分:0)
解决方案:
$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中工作:)
答案 10 :(得分:0)
如果仍然有人在努力使用insert_batch来使用ignore,
检查此路径,
system/database/DB_query_builder.php
搜索功能
protected function _insert_batch
更改
INSERT INTO => INSERT IGNORE INTO
稍后谢谢我。 :)
答案 11 :(得分:0)
避免在codeigniter中插入重复数据是一项棘手的任务。但是您可以以非常简单和准确的方式使用自定义库方法忽略重复值插入。 我在以下位置找到了合适的解决方案: how-to-avoid-duplicate-data-insertion-in-codeigniter-php
答案 12 :(得分:-1)
通过在数据库表中为至少一个字段设置唯一键来避免重复行。