web-dev-qa-db-ja.com

Codeigniter-複数のWHERE条件を使用したバッチ更新

手始めに、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();

指定したデータに基づいて更新文字列を生成し、クエリを実行します。 arrayまたはobjectを関数に渡すことができます。配列を使用した例を次に示します。

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

最初のパラメーターにはテーブル名が含まれ、2番目のパラメーターは値の連想配列であり、3番目のパラメーターはwhereキーです。

出典:

16
zechdc

update_batch()に複数のwhere句を追加することはできません。 where句の3番目のパラメーターとして文字列のみを受け入れるため、メソッドが現在記述されている方法でこれを行う方法はないと確信しています。

ソース から:

/**
 * 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)
19
Chris Schmitz

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'

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');
}
10
Rodrigo Prazim

WHEREクエリがバッチループでクリアされているため、_update_batch_で複数の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->qb_where = array();によってクリアされることに注意してください。

CodeIgniter v3.1.10では、問題のある行は1940年の_DB_query_builder.php_にあります。これにより、WHERE条件が処理された最初のバッチ(デフォルトは100)で機能し、後続のバッチで失敗するという非常に予期しない動作が発生します。

2つの可能な解決策があります:

  1. _batch_size_の4番目の_update_batch_パラメーターを使用し、100,000などの大きな数値を渡すと、すべてのクエリが最初のバッチで処理され、WHERE条件がクリアされません。
  2. 問題のある行を更新して、最初の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;
        }
_

これがお役に立てば幸いです。

0
Ray Li