LoginSignup
2
0

More than 1 year has passed since last update.

自作バルクアップデート

Posted at

ざっくりBULK INSERT(バルクインサート)の説明

複数のINSERT処理を行う場合、1行ごとにINSERT文を書いてSQLを流すことで処理することができます。

/* 例文 */
INSERT INTO users (name, age) VALUES ('tanaka', 23);
INSERT INTO users (name, age) VALUES ('suzuki', 29);
INSERT INTO users (name, age) VALUES ('makihara', 26);

ただ、上記の記述ではSQLが1行1行処理されるためデータの数が多くなる程処理が重くなっていきます。

それを軽くするのがバルクインサート
1行にすべてのINSERT文をまとめて書くことで処理が軽くなっていきます

/* 例文 */
INSERT INTO users (name, age) VALUES ('tanaka', 23),('suzuki', 29),('makihara', 26);

BULK INSERTを真似してBULK UPDATE(バルクアップデート)をしたい

上記のサイトのコードをもとにBULK INSERT文を書き換えて、
UPDATE INTO users (id, name, age) VALUES (1, 'tanaka', 23),(2, 'suzuki', 29),(3, 'makihara', 26);みたいに出来ればいいだけどなーと思ったけども
そんなに甘いわけではなかったみたいでいろいろ調べてみたところ

上記の記事に書かれていたREPLACEに書き換えるやり方が楽そうだなぁーと思いつつ、読んでいると

uniqueキーがかぶった場合の内部挙動は、「UPDATE文」ではなく、「DELETE文 + INSERT文」

この一言でREPLACEでの対応が難しくなってしまいました。
(テーブルの一部のカラムのみ更新をかける処理に使いたいため、DELETED+INSERTではデータを渡していないカラムのデータが空になってしまうため)

それではBULK UPDATE

渋々、上記の記事で書かれていたELTとFIELDを使った方法でBULK UPDATEの処理をしてくれる関数を作成

//関数に渡す配列データの例
$data = [
    ['id' => 1, 'age' => 23, 'name' => 'tanaka'],
    ['id' => 2, 'age' => 29, 'name' => 'suzuki'],
    ['id' => 3, 'age' => 26, 'name' => 'makihara']
];

AppModel.php
/**
 * bulkUpdate
 *
 * @param array $data
 * @return boolean
 */
public function bulkUpdate($data) {
    //対象テーブル名
    $table_name = $this->table;
    //対象カラム名のリスト
    $fields = array_keys($data[0]);

    //idのリスト作成
    $ids = implode(',', array_column($data, 'id'));

    //IDの削除
    $key = array_search('id', $fields);
    unset($fields[$key]);

    //SQL文の作成
    $sql = "UPDATE `{$table_name}` SET ";
    $params = [];
    foreach($fields as $field){
        $values = array_column($data, $field);
        //変更するIDを列挙
        $sql .= " `{$field}` = ELT(FIELD(id, {$ids} ),";

        //対象のカラムのパラメータの数だけ「?」を列挙
        $sql .=   implode(", ", array_fill(0, count($values), '?')) . "),";

        //パラメーターを配列に代入
        foreach ($values as $value){
            $params[] = $value;
        }
    }

    //文末のカンマ削除
    $sql = substr($sql, 0, -1);
    $sql .= " WHERE id IN ({$ids});";

    $query = $this->query($sql, $params);
    if ($query === false) {
        return false;
    }
    return true;
}

普通のPHPで使う場合は$table_name = $this->table;$query = $this->query($sql, $params);をPHP用に書き換えればつかるかな

これで、処理が軽くなるといいんだけどな。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0