Laravel使用每个记录的不同值更新多个记录

tnkciper  于 2022-12-14  发布在  其他
关注(0)|答案(4)|浏览(146)

我想用不同的值更新多个记录。我应该用laravel proficent做什么?这是我的代码示例。提前感谢。

$employee_presences = Employee_presence::
    where('employee_id', $report_history->employee_id)
    ->whereBetween('presence_date',[$report_history->report->start_period,$report_history->report->end_period])
    ->get();

    foreach ($presences_data as $presence_data) 
    {
        foreach ($employee_presences as $employee_presence)
        {
            $updated_presences = Employee_presence::
            where('id', $employee_presence->id)->update([
                'presence_value' => $presence_data['presence_value']
            ]);
        }
    }

这些是**$presences_data**中的值。这是用于更新记录的新数据。

以下是记录**$employee_presences**:

k4aesqcs

k4aesqcs1#

无法在同一个查询中使用不同的数据来更新多个记录。您可以对每个变更群组执行一个查询来大量更新记录:

Employee_presence::whereIn('employee_id', <list of ids>)->update(
    [
        'presence_value' => 1,
        'presence_date' => "2021-07-12"
    ]
);

Employee_presence::whereIn('employee_id', <different ids>)->update(
    [
        'presence_value' => 0.5,
        'presence_date' => "2021-07-13"
    ]
);

如果没有组(意味着每个记录都有不同的值),则需要在不同的查询中分别更新它们。效率不是很高。

tyky79it

tyky79it2#

通过使用mysql CASE语句是可能的。AFAIK在proficent中没有内置函数或case语句的查询构建器,所以你必须用原始语句来完成查询的这一部分。
我真的不明白在你的例子中你想要哪个值对应哪个记录(可能是我的错),但是我会尽我所能用一个你可以通用的函数来帮助你:
假设您要从员工中选择要更新的员工id,并且对于每个员工id,您还知道要给予它们的presence值。您可以创建一个数组$data,其中这些id是键,presence值是值。然后您可以在以下函数中抛出该数组:

public static function updatePresencePerEmployee($data){
    //make the complex case statement first
    $case = "(case";
    foreach ($data as $employee_id => $presence_value ){
        $case.=" when employee_id = ".$employee_id." then ".$presence_value;
    }
    $case.=" end)";

    DB::table('employee_presence')
        //shift the keys of the array which are employee id's to values so laravel can use it in the whereIn clause
        ->whereIn('employee_id', array_keys($data))
        //dont forget to throw the case string in to the DB:raw function
        ->update(['presence_value' =>DB::raw($case)]);
}

我在我的一个应用程序中使用了这个函数,但是它需要改进。例如,现在你需要确保case语句中的那些值不是sql注入。
如果你不明白发生了什么,阅读这个线程会有所帮助。它告诉你如何使用case语句。
MySQL - UPDATE multiple rows with different values in one query

xoefb8l8

xoefb8l83#

我不完全确定MySQL,但它适用于SQL Server。
首先,构建要更新的数据的集合- column_name =〉$value,包括ID
然后从中创建一个“值列表”,如下所示

$value_items = $update_array->map(function ($entry) {
    if (!isset($entry)) {
        return 'NULL';
    }
    if (is_iterable($entry)) {
        return collect($entry)
            // Wrap strings in quotes
            ->map(fn($item) => isset($item)
                ? (is_string($item) ? "'$item'" : $item)
                : 'NULL'
            )
            ->join(',');
    }
    if (is_string($entry)) {
        return "'$entry'";
    }
    return $entry;
})
->map(fn($rows) => '(' . $rows . ')')
->join(',');

这将给予一个字符串沿着其形式为(1, 'foo', 'bar'), (2, 'foo', 'bar')
将该值列表转换为原始子查询

$sub_query = "SELECT * FROM (VALUES $value_items) AS sub_query (id, column_one, column_two, etc)";

执行更新查询

YourModel::query()
  ->joinSub($sub_query, 'values_list_alias', 'values_list_alias.id', 'your_model.id')
  ->update([
    'column_one' => DB::raw('values_list_alias.column_one'),
    'column_two' => DB::raw('values_list_alias.column_two')
  ]);
y1aodyip

y1aodyip4#

一种方法是使用upsert https://laravel.com/docs/9.x/eloquent#upserts

Flight::upsert([
    ['presence_value' => '...', 'presence_date' => '...', 'employee_id' => 99],
    ['presence_value' => '...', 'presence_date' => '...', 'employee_id' => 150]
], ['employee_id', 'presence_date'], ['presence_value']);

相关问题