CodeIgniter - 如果新的或更新的重复记录则插入活动记录

Posted

技术标签:

【中文标题】CodeIgniter - 如果新的或更新的重复记录则插入活动记录【英文标题】:CodeIgniter- active record insert if new or update on duplicate 【发布时间】:2015-06-01 20:20:28 【问题描述】:

是否可以在 CodeIgniter 中执行 活动记录 查询,如果现有记录已存在则更新现有记录,如果不存在则插入给定键?

我知道这可以通过首先查询找到现有记录来完成,但我正在寻找最有效的方法。

【问题讨论】:

提交时检查item是否有id 【参考方案1】:

基本上您正在寻找的可能是这个 INSERT ... ON DUPLICATE KEY UPDATE - 前提是您使用的是 mysql 并且您的 id 是表上的唯一键。

您必须手动构造查询并将其传递给 $this->db->query() 函数,而不是像 DB 驱动程序的帮助函数那样的任何内置活动记录。

示例:

$sql = 'INSERT INTO menu_sub (id, name, desc, misc)
        VALUES (?, ?, ?, ?)
        ON DUPLICATE KEY UPDATE 
            name=VALUES(name), 
            desc=VALUES(desc), 
            misc=VALUES(misc)';

$query = $this->db->query($sql, array( $id, 
                                       $this->validation->name, 
                                       $this->validation->desc, 
                                       $this->validation->misc
                                      ));

【讨论】:

这是活动记录吗? 显然不是,如果您正在构建自己的查询。【参考方案2】:

如果您使用 Codeigniter 3.0 或更高版本,您可能需要考虑使用“$this->db->replace()”。根据用户指南:

"这个方法执行一个REPLACE语句,这基本上是(可选)DELETE + INSERT的SQL标准,使用PRIMARY和UNIQUE键作为决定因素。在我们的例子中,它将使您无需实现复杂的逻辑使用 select()、update()、delete() 和 insert() 调用的不同组合。"

换句话说,

如果不存在,则插入一条新记录。 如果确实存在,它会根据其主键或唯一键对其进行更新。

开箱即用,如:

$data = array(
        'title' => 'My title',
        'name'  => 'My Name',
        'date'  => 'My date'
);

$this->db->replace('table', $data);

不需要电池!!!

【讨论】:

但是这个更新有问题,当有自动增量id时,replce时它会增加 @SameeraPrasadJayasinghe "... REPLACE INTO 基本上删除该行(如果存在),并插入新行..." - 来自 Dale 对此处答案的评论:***.com/a/4205222/1475817【参考方案3】:

你可以做得更简单:

$sql = $this->db->insert_string(table, $array) . ' ON DUPLICATE KEY UPDATE ' .
implode(', ', $array);
$this->db->query($sql);

【讨论】:

这是不完整的,不会像发布的那样工作。 implode 只会组合数组值,不带引号和字段名称。如果您将主键作为其中之一传递,它将被包括在内,这是不应该的。【参考方案4】:

我不知道 Codeigniter Active Record 类有这个方法还是不检查codeigniter docs 是否包含在活动记录类中的方法

但是您可以通过扩展 codigniter 的核心模型来实现这一目标。 通过使用这种方式,您可以将此方法用于扩展此模型类的所有模型。 只需将MY_model.php 放入 application/core/ 并编写以下代码即可。

Class MY_Model extends CI_Model

  public function insert_update($data)
  
       // code for checking existing record.
       if(//existing record)
           fire the update query
       else
           fire the insert query

       return insert/update id;

  

创建上述文件后,您必须将所有模型父类更改为新的扩展模型,即 MY_Model

class some_model extends MY_Model

注意:您必须从结果中选择主键并将其放入 where 条件中。

这是非常关键的,所以当我从控制器获取数据时我会检查它是否有 ID,如果 Id 存在则我触发更新查询,然后我触发插入查询。

祝你好运

【讨论】:

OP 已经知道这种方法。他想知道任何可用的有效方法。【参考方案5】:

我正在使用这种方法:

    使用unique idunique 键为您要更新的column xyz 配置您的表mytable

    尝试插入数组$data,使用INSERT IGNORE INTO避免重复

    $insert_query = $this->db->insert_string('bt_ical_list', $data);
    $insert_query = str_replace('INSERT INTO','INSERT IGNORE INTO',$insert_query);
    $this->db->query($insert_query); 
    

    如果column xyz 中的值不存在,则插入一行

    如果插入了行,则使用函数insert_id() 返回id,如果没有插入行,则更新。

    if(!$this->db->insert_id())
        $query=$this->db    ->where('xyz', $data['xyz'])
                            ->update('my_table',$data);
    ;  
    

【讨论】:

【参考方案6】:

这是一个我希望可以完成同样的方法

   /**
    * Used to insert new row if a duplicate entry is encounter it performs an update
    * @param string $table table name as string
    * @param array $data associative array of data and columns
    * @return mixed 
    */
   private function updateOnExist($table, $data)
   
        $columns    = array();
        $values     = array();
        $upd_values = array();
        foreach ($data as $key => $val) 
            $columns[]    = $this->db->escape_identifiers($key);
            $val = $this->db->escape($val);
            $values[]     = $val;
            $upd_values[] = $key.'='.$val;
        
        $sql = "INSERT INTO ". $this->db->dbprefix($table) ."(".implode(",", $columns).")values(".implode(', ', $values).")ON DUPLICATE KEY UPDATE".implode(",", $upd_values);
        return $this->db->query($sql);

【讨论】:

【参考方案7】:

如果 Marcos Sánchez Urquiola 在 his answer 中建议的替换解决方案对您不起作用,因为您有一个自动增量列,以下是最简洁的方法,同时避免自己引用/清理输入并让 Codeigniter这样做。

$table = 'database.table'; // Usually you would have this in you model
$primary_key = 'id'; // You would also have this in you model

$data = [
    'id' => '14',
    'name' => 'John Smith',
    'email' => 'john.smith@devnullmail.com',
];

// get keys and remove primary_key if it has been included in the data array
$updates_array = array_filter( array_keys($data), function($fieldName) use ($primary_key)  return $fieldName !== $primary_key; );
array_walk($updates_array, function(&$item) $item = "$item=VALUES($item)";  );

$sql = $this->db->insert_string($table, $data) . ' ON DUPLICATE KEY UPDATE ' . implode(', ', $updates_array);

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

/*
Generates an insert statement with the following at the end:
    ON DUPLICATE KEY UPDATE
        name=VALUES(name),
        email=VALUES(email)
This way you work with the values you already supplied to $this->db->insert_string
*/

【讨论】:

【参考方案8】:

更新了米拉扎的回答—— 搞定了

    $updt_str = '';
    foreach ($array as $k => $v) 
        $updt_str = $updt_str.' '.$k.' = '.$v.',';
    
    $updt_str = substr_replace($updt_str,";", -1);
    $this->db->query($this->db->insert_string('table_name', $array).' ON DUPLICATE KEY UPDATE '.$updt_str);

【讨论】:

不仅值没有被引用,它们也没有被清理或转义

以上是关于CodeIgniter - 如果新的或更新的重复记录则插入活动记录的主要内容,如果未能解决你的问题,请参考以下文章

插入批处理,如果在Codeigniter 3 HMVC中有重复的密钥更新

插入并返回插入的行数(非重复)和记录 ID(新的或重复的)

仅向红移表添加新的或修改的数据

Codeigniter 如果不存在则插入,如果不存在则更新

Codeigniter 3 - 会话不工作

codeigniter:在非条件下查询 [重复]