Codeigniter - 具有多个 Where 条件的批量更新

Posted

技术标签:

【中文标题】Codeigniter - 具有多个 Where 条件的批量更新【英文标题】:Codeigniter - Batch Update with Multiple Where Conditions 【发布时间】:2011-11-17 13:44:47 【问题描述】:

对于初学者,关于 update_batch 的 Codeigniter 文档不存在。 kenjis 提供了一些文档并将其提交到存储库。希望他们尽快把它拉出来。

有谁知道如何在 Codeigniters update_batch 命令中添加多个 where 条件?

我的预期用途:

$where = array(
    'title',
    'name'
); 

$this->db->update_batch('mytable', $data, $where);

当我尝试此代码时,出现以下错误:

A Database Error Occurred
One or more rows submitted for batch updating is missing the specified index.

Filename: C:\wamp\www\wheel\system\database\DB_active_rec.php

Line Number: 1451

kenjis 更新批量文档:

$this->db->update_batch();

根据您提供的数据生成更新字符串,并运行查询。您可以将 arrayobject 传递给函数。下面是一个使用数组的例子:

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

$this->db->update_batch('mytable', $data, 'title');
// Produces: 
// UPDATE `mytable` SET `name` = CASE
// WHEN `title` = 'My title' THEN 'My Name 2'
// WHEN `title` = 'Another title' THEN 'Another Name 2'
// ELSE `name` END,
// `date` = CASE 
// WHEN `title` = 'My title' THEN 'My date 2'
// WHEN `title` = 'Another title' THEN 'Another date 2'
// ELSE `date` END
// WHERE `title` IN ('My title','Another title')

第一个参数将包含表名,第二个是一个关联数组,第三个参数是 where 键。

来源:

kenjis 的文档更新: https://bitbucket.org/kenjis/ci-user-guide/changeset/3d579dd14afe saintnicster 的拉取请求:https://github.com/EllisLab/CodeIgniter/pull/448

【问题讨论】:

【参考方案1】:

您不能将多个 where 子句添加到 update_batch()。它只接受一个字符串作为 where 子句的第三个参数,所以我确信没有办法按照当前编写方法的方式执行此操作。

来自source:

/**
 * Update_Batch
 *
 * Compiles an update string and runs the query
 *
 * @param   string  the table to retrieve the results from
 * @param   array   an associative array of update values
 * @param   string  the where key
 * @return  object
 */
public function update_batch($table = '', $set = NULL, $index = NULL)

【讨论】:

太糟糕了,如果最后有第四个参数,那将是一个很好的补充。如果您直接使用 SQL,则可以在 UPDATE 查询的末尾添加一个“AND”。这似乎产生了预期的效果,例如:UPDATE mytable SET ... WHERE id IN(1,2,3) AND mycategory = 44【参考方案2】:

我正在使用 codeigniter 3.1.5 并且遇到了同样的问题,但我解决了我的问题如下:

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

$this->db->where('name','My Name 2');
$this->db->update_batch('mytable', $data, 'title');

生产它:

// Produces:
// UPDATE `mytable`
// SET `name` = CASE
//     WHEN `title` = 'Another title' THEN 'Another Name 2'
//     WHEN `title` = 'My title' THEN 'My Name 2'
//     ELSE `name`
// END,
//     `date` = CASE 
//     WHEN `title` = 'My title' THEN 'My date 2'
//     WHEN `title` = 'Another title' THEN 'Another date 2'
//     ELSE `date`
// END
//     WHERE `title` IN ('My title','Another title')
// AND `name` = 'My Name 2'

更新

我在尝试使用 update_batch 添加超过 100 条记录时遇到问题,例如:

$data = [1=>a,2=>b ... 200=>zz];

第一次调用(使用 WHERE):

// Produces:
// UPDATE `mytable`
// SET `name` = CASE
//    WHEN `title` = 'My title' THEN 'My Name 2'
//    WHEN `title` = 'Another title' THEN 'Another Name 2'
//    ELSE `name`
// END,
//  `date` = CASE 
//    WHEN `title` = 'My title' THEN 'My date 2'
//    WHEN `title` = 'Another title' THEN 'Another date 2'
//    ELSE `date`
// END
//    WHERE `title` IN ('My title','Another title')
//    AND `name` = 'My Name 2'

第二次调用(没有 WHERE):

// Produces:
// UPDATE `mytable`
// SET `name` = CASE
//      WHEN `title` = 'My title' THEN 'My Name 2'
//      WHEN `title` = 'Another title' THEN 'Another Name 2'
//      ELSE `name`
// END,
//      `date` = CASE 
//      WHEN `title` = 'My title' THEN 'My date 2'
//      WHEN `title` = 'Another title' THEN 'Another date 2'
//      ELSE `date`
// END
//      WHERE `title` IN ('My title','Another title')

试试这个:

$chunk1 = array_chunk($data,100);
for($i=0;$i < count($chunk1);$i++) 
   $this->upload_model->update_data($chunk1[$i],'My Name 2');

型号:

public function update_data($data='',$name='')
   $this->db->where('name',$name);
   $this->db->update_batch('mytable', $data, 'title');

【讨论】:

记住,我的第二个索引是静态值 哇,伙计,你是个开箱即用的思想家。我永远不会这样想。谢谢 如果你能想到第二个索引也是动态的方法! 最好将update_batch的第三个参数包含在public function update_data的参数中 不行,看看我的论坛帖子:forum.codeigniter.com/thread-68561.html【参考方案3】:

update_batch 中的多个 where 条件被破坏,因为批处理循环中正在清除 WHERE 查询。

这里是批量更新循环:

        for ($i = 0, $total = count($this->qb_set_ub); $i < $total; $i += $batch_size)
        
            if ($this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set_ub, $i, $batch_size), $index)))
            
                $affected_rows += $this->affected_rows();
            

            $this->qb_where = array();
        

请注意,传递的 WHERE 条件被 $this-&gt;qb_where = array(); 清除。

在 CodeIgniter v3.1.10 中,违规行位于 DB_query_builder.php 中的 1940 上。这会产生一个非常意外的行为,其中 WHERE 条件适用于第一个处理的批次(默认 100),而后续批次则失败。

有两种可能的解决方案:

    使用update_batch的第4个batch_size参数,并传入100,000这样的大数,这样所有的查询都会在第一批中处理,不会清除WHERE条件。 更新违规行以恢复初始 WHERE 条件。

解决方案 #2 的代码:

        // Save initial where conditions.
        $where_holder = $this->qb_where;
        // Batch this baby
        $affected_rows = 0;
        for ($i = 0, $total = count($this->qb_set_ub); $i < $total; $i += $batch_size)
        
            if ($this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set_ub, $i, $batch_size), $index)))
            
                $affected_rows += $this->affected_rows();
            

            // Restore intial where conditions.
            $this->qb_where = $where_holder;
        

希望这有帮助!

【讨论】:

【参考方案4】:
Try this one also !
Suppon you have import data through csv/excel
then store all record in single array like:

Array
(
    [0] => Array
        (
           
            [price] => 100.00
            [part_no] => PD001
            [brand] => 44
            [special_price] => 90.10

        )

    [1] => Array
        (
            
            [price] => 200.00
            [part_no] => PD002
            [special_price] => 150.00
           
        )

)

Step 2:
Call to model
$model = new CatalogModel();
$result = $model->batchUpdateData($final_array);


function batchUpdateData($array = array())

  $query = $this->db->table('product');
  $price = array();
  $part_no = array();
  $special = array();
  $brand = array();

  if (!empty($array)) 
   foreach ($array as $key => $value) 
    $price[] = $value['price'];
    $part_no[] = $value['part_no'];
    $special[] = $value['special_price'];
    $brand[] = $value['brand'];

  
  
    $num = count($part_no);
    $sql ="UPDATE product SET "; 
   
   //  price colum update
     $sql .=" price = CASE ";
     for($i=0; $i < $num; $i++)
     $sql .=" WHEN  part_no = '".$part_no[$i]."' AND brand = '".$brand[$i]."'  THEN '".$price[$i]."' ";

    
    $sql .="ELSE price END ,";
    
    // special colum update
    $sql .=" special_price = CASE ";
    for($i=0; $i < $num; $i++)
    $sql .=" WHEN  part_no = '".$part_no[$i]."' AND brand = '".$brand[$i]."'  THEN '".$special[$i]."' ";

    
    $sql .="ELSE special_price END";
    

   $sql .=" WHERE part_no IN ('" . implode("','", $part_no) . "') ";

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

 



This will product query like:
UPDATE `product` SET `price` = CASE WHEN `part_no` = 'PD001'  and `brand` = '44' THEN '100.00' WHEN `part_no` = 'PD002'  and `brand` = '44' THEN '200.00' ELSE `price` END 
WHERE `part_no` IN('PD001','PD002');

If this helpfull give a thumbs up

【讨论】:

请编辑您的答案,并提供有关代码功能的其他信息。见How to answer。

以上是关于Codeigniter - 具有多个 Where 条件的批量更新的主要内容,如果未能解决你的问题,请参考以下文章

多个where条件codeigniter

CodeIgniter:如何使用活动记录将一个列值移动到另一个具有 Where 条件的值

使用多个 WHERE 子句更新 Codeigniter 中的批处理

使用 CodeIgniter 的 ActiveRecord 对多个条件逻辑进行分组

从 Codeigniter db 类获取编译的 WHERE 语句

带有Codeigniter中If条件的MySQL get_where