如何使用关联数组更新所有记录?

Posted

技术标签:

【中文标题】如何使用关联数组更新所有记录?【英文标题】:How can i UPDATE all records using associative array? 【发布时间】:2021-06-20 13:42:08 【问题描述】:

我有一张包含我的网站设置的表格:

我想使用来自表单的数据一次更新所有记录。 数据如下所示:

$data = [
  "brand" => "bbb"
  "mail" => "kontakt@aaa.pl"
  "phone" => "111"
  "site-name" => "test"
];

现在我想用关联数组的键和它的值来更新它。 我试过了:

DB::table('settings')->update($data);

但是有一个错误:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'brand' in 'field list' (SQL: update `settings` set `brand` = bbb, `mail` = kontakt@aaa.pl, `phone` = 111, `site-name` = test)

显然它认为brand 是一个列名。 所以我将$data 转换为这个数组:

$data = [
  0 => [
    "name" => "brand"
    "value" => "bbb"
  ]
  1 => [
    "name" => "mail"
    "value" => "kontakt@aaa.pl"
  ]
  2 => [
    "name" => "phone"
    "value" => "111"
  ]
  3 => [
    "name" => "site-name"
    "value" => "test"
  ]
];

现在错误是:

SQLSTATE[42S22]: Column not found: 1054 Unknown column '0' in 'field list' (SQL: update `settings` set `0` = "name":"brand","value":"bbb", `1` = "name":"mail","value":"kontakt@aaa.pl", `2` = "name":"phone","value":"111", `3` = "name":"site-name","value":"test")

所以现在它认为数组中每一行的索引是列名,在这个地方我不知道该怎么做...... 谁能帮帮我?

【问题讨论】:

我想这个问题在这里已经有了答案:***.com/questions/25674737/…> 你应该清楚你的意图。 【参考方案1】:

您可以使用upsert更新多条记录

首先转换数据以使用集合添加列名

$data=collect($data)->transform(function ($value,$name)
        return ["name"=>$name,"value"=>$value];
    )->values()->toArray();

这里我使用了模型

Setting::upsert($data,["name"],["value"]);

了解Upserts

    Upsert 在单个查询中执行多个“upsert”

    第一个参数包含要插入或更新的值

    第二个参数列出了在关联表中唯一标识记录的列。

    第三个也是最后一个参数是一个列数组,如果数据库中已经存在匹配记录,则应该更新这些列。

同样重要的一点

除 SQL Server 之外的所有数据库系统都需要 提供给 upsert 方法的第二个参数具有“主要”或 “唯一”索引。

这意味着在您的 mysql 表设置列中 nameunique index 否则它将作为新行插入

参考:https://laravel.com/docs/8.x/eloquent#upserts

【讨论】:

【参考方案2】:

您的表格看起来就像您只能获取一组数据并随时间更新。为什么是因为没有外键关系。

如果是这种情况,那么为什么不在设置列中设置品牌名称、邮件、电话和站点名称,

您的迁移

public function up()

    Schema::create('settings', function (Blueprint $table) 
        $table->string('brand_name');
        $table->string('mail');
        $table->string('phone');
        $table->string('site_name');
        $table->timestamps();
    );

在你的模型中?

protected $fillable = ['brand_name', 'mail', 'phone', 'site_name'];

protected $guarded = [];

在你的控制器中

public function method(Request $request)

    // You can also abstract this in to a custom request class
    $request->validate([
        'brand_name' => 'required',
        'mail' => 'required',
        'phone' => 'required',
        'site_name' => 'required',
    ]);
    
    // Add data if record doesn't exist, update when it does
    // To use the validated method on request all needed fields must be required
    Settings::updateOrCreate($request->validated())


万一我错了,你仍然可以查看 Laravel 大规模更新 https://laravel.com/docs/8.x/eloquent#mass-updates

Laravel Upserts https://laravel.com/docs/8.x/eloquent#upserts

【讨论】:

问题是随着时间的推移我计划添加更多设置,这意味着使用您的解决方案会有更多行或更多列。所以我必须坚持行。无论如何感谢您的回答【参考方案3】:

我来到了这个解决方案,虽然我认为它看起来很丑,应该有更好的方法来做到这一点,如果没有更好的答案,我会将我的答案标记为正确

$data = [
  "brand" => "bbb"
  "mail" => "kontakt@aaa.pl"
  "phone" => "111"
  "site-name" => "test"
];

foreach($data as $key=>$d) 
      DB::table('settings')->where('name','=',$key)->update(['value' => $d]);

【讨论】:

以上是关于如何使用关联数组更新所有记录?的主要内容,如果未能解决你的问题,请参考以下文章

如何以及在哪里处理关联记录的更新过程?

如何通过节点js中的sequelize更新关联记录?

php:如何通过键更新关联数组中的值

如何使用nodejs更新mysql json数组

如何使用 graphql 更新集合中的所有记录

如何在 SQL 中选择有关联的记录?