【问题标题】:Laravel 5.2 update/insert batch similar to Codeigniter's update_batch/insert_batch()Laravel 5.2 更新/插入批处理类似于 Codeigniter 的 update_batch/insert_batch()
【发布时间】:2015-12-29 15:02:08
【问题描述】:

laravel 有类似 Codeigniter 的批量更新功能吗?

Codeigniter 使用$this->db->update_batch('mytable', $data, 'title'); 进行批量更新。更多信息可以在here找到。

但是对于laravel的update,好像只能做单笔交易。我觉得当你有多行要更新时,这有点糟糕,其中它将在一个 for 循环中。类似的东西:

foreach ($rows => $row) {
    DB::table('users')->where('id', $row['row_id'])->update(['votes' => 1]);
}

至少你得到了图片,对吧?

如果您查看此代码,您的数据库可能会被淘汰,因为它会继续连接,这与 update_batch() 不同,只会抛出一个事务。

【问题讨论】:

    标签: php database codeigniter laravel laravel-5


    【解决方案1】:

    TL;DR - 不清楚 CodeIgniter (CI) 方法是否比一系列 UPDATE 查询更有效。另外,CI方法不如UPDATEs的循环系列清晰。

    说 Laravel “继续连接”是不正确的——它会在请求开始时打开一个连接并继续使用该连接直到请求完成。我认为您的意思是您正在向服务器发送大量查询。

    这样做是真的:

    INSERT INTO table VALUES (1, ...);
    INSERT INTO table VALUES (2, ...);
    INSERT INTO table VALUES (3, ...);
    ...
    INSERT INTO table VALUES (n, ...);
    

    会比这样做效率低:

    INSERT INTO table VALUES (1, ...),
    (2, ...),
    (3, ...),
    ...
    (n, ...);
    

    但这不是一个简单的INSERT。在您发布的链接中查看 CI 库生成的代码。我们正在研究的是以下之间的效率差异:

    UPDATE table SET value=1 WHERE id=1;
    UPDATE table SET value=2 WHERE id=2;
    UPDATE table SET value=3 WHERE id=3;
    ...
    UPDATE table SET value=n WHERE id=n;
    

    UPDATE table
    SET value = CASE
        WHEN id = 1 THEN 1
        WHEN id = 2 THEN 2
        WHEN id = 3 THEN 3
        ...
        WHEN id = n THEN n
        ELSE value END
    WHERE id IN (1, 2, 3, ..., n);
    

    我不是 SQL 专家,但我不相信第二个比第一个更有效。 WHEN 子句的长链将由 SQL 服务器处理 - 一堆简短的 UPDATE 语句(在我看来)会更有效,特别是当您在 @ 中使用索引列时987654330@子句。

    最后,查看 CI 文档,update_batch 方法对您传递给它的数据结构做了一些假设 - 例如,数组中的第一项是更新语句的键。当您在六个月后查看您的代码时,这一点(至少对我而言)不会很清楚。

    【讨论】:

    • 许多更新与何时:我对此进行了测试,我的答案是需要平衡。最慢的是 not 使用 WHEN 和使用 WHEN a lot。最快的是使用少量的 WHEN(即小块)。
    • 顺便说一句,“效率会更高,尤其是当您在 WHERE 子句中使用索引列时”——这两种情况都是如此。
    【解决方案2】:

    也许会有所帮助

    trait InsertOrUpdate {
    static function InsertOrUpdate(array $rows) {
        $table = DB::getTablePrefix().with(new self)->getTable();
        if (empty($table)) {
            return false;
        }
        $maxRowData = DB::table($table)->where('id', DB::raw('(select max(`id`) from ' . $table . ')'))->first();
        if (! empty($maxRowData)) {
            $maxId = $maxRowData->id;
            $result = DB::statement('ALTER TABLE ' . $table . ' AUTO_INCREMENT = ' . $maxId . ';');
        }
        $tableColumns = DB::getSchemaBuilder()->getColumnListing($table);
        $datetime = Carbon::now()->toDateTimeString();
        if (in_array('created_at', $tableColumns)) {
            foreach ($rows as $key => $row) {
                $rows[$key]['created_at'] = $datetime;
                $rows[$key]['updated_at'] = $datetime;
            }
        }
        $first = reset($rows);
        $columns = implode(',',
            array_map(function($value) {
                return "$value";
            },
            array_keys($first))
        );
    
        $values = implode(',', array_map(function($row) {
                return '('.implode( ',',
                    array_map(function($value) { return '"' . str_replace('"', '""', $value) . '"'; }, $row)
                ).')';
            } , $rows)
        );
    
        $updates = '';
        if (in_array('updated_at', $tableColumns)) {
            unset($first['created_at']);
            unset($first['updated_at']);
            $first['deleted_at'] = NULL;
    
            $updateString = '(CASE WHEN ';
            $lastClolumn = count($first);
            $columnNum = 1;
            foreach (array_keys($first) as $column) {
                $updateString .= $column . ' <> VALUES(' . $column . ')';
                if ($columnNum != $lastClolumn) {
                    $updateString .= ' OR ';
                }
                $columnNum++;
            }
            $updateString .= ' THEN \'' . $datetime . '\' ELSE `updated_at` END), ';
            $updates .= 'updated_at = ' . $updateString;
        }
        $updates .= implode(',',
            array_map(function($value) {return "$value = VALUES($value)"; } , array_keys($first) )
        );
        $sql = "INSERT INTO {$table}({$columns}) VALUES {$values} ON DUPLICATE KEY UPDATE {$updates};";
        return DB::statement($sql);
    }
    

    【讨论】:

      【解决方案3】:

      【讨论】:

      • 当您有多个井时使用事务,事务(如更新然后执行插入/删除等)。我想要做的是只有一个更新语句可以同时更新多行。
      • 看起来您可能必须使用原始表达式。 laravel.com/docs/5.2/database#running-queries
      猜你喜欢
      • 2020-09-17
      • 1970-01-01
      • 2017-04-01
      • 2017-08-19
      • 2017-06-11
      • 2019-06-12
      • 2011-09-10
      • 1970-01-01
      相关资源
      最近更新 更多