【问题标题】: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"})

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

【问题讨论】:

  • 我想这个问题在这里已经有了答案:stackoverflow.com/questions/25674737/…>
  • 你应该清楚你的意图。

标签: php mysql sql laravel laravel-8


【解决方案1】:

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

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

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

这里我使用了模型

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

了解Upserts

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

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

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

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

同样重要的一点

除 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]);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-14
      • 2021-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多