0

I need to find the minimum "priority" value and then set it's value to another entry, in place using laravel eloquent.

Is there any way to do so or any best practice for it?

What I have in mind :

Orders::where('user_id', '!=', $user_id)
 ->where('odm_id', $odm_id)
 ->whereExpired(0)
 ->min('priority')
 ->update(['priority' => 1]);

FYI: Above approach is giving an error and is not working. The Error Message is :

Call to a member function update() on string
Mohammad_Hosseini
  • 2,191
  • 2
  • 23
  • 48

1 Answers1

1

The problem is that min will return a number and not an actual model. If you want the actual model which has the min value you need to something like:

Orders::where('user_id', '!=', $user_id)
        ->where('odm_id', $odm_id)
        ->wherePriority(function ($query) use ($user_id, $odm_id) {
        $query->from(\DB::raw('(SELECT * FROM orders) AS o'))
              ->selectRaw("MIN(`o`.`priority`)")                   
              ->where('o.odm_id', $odm_id)
              ->where('o.expired', 0);
        })->update(['priority' => 1]);

Note that this will update all records which have expired 0, odm_id equal to $odm_id and match the minimum value.

Alternatively you can do:

$orders =Orders::where('user_id', '!=', $user_id)
        ->where('odm_id', $odm_id)
        ->wherePriority(function ($query) use ($user_id, $odm_id) {
        $query->from(\DB::raw('(SELECT * FROM orders) AS o'))
              ->selectRaw("MIN(`o`.`priority`)")                   
              ->where('o.odm_id', $odm_id)
              ->where('o.expired', 0);
        })->get();

  $orders->each(function ($order) {
       $order->priority = 1;
       $order->save();
  });

The second way has the disadvantage of doing 2 separate queries, one to get the data and one to update, however this has the advantage of triggering model events such as saving etc.

apokryfos
  • 30,388
  • 6
  • 55
  • 83
  • I've used your method but the problem is it gives me this error : "SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where `odm_id` = ? and `expired` = ?)' at line 1 (SQL: update `orders` set `priority` = 1, `updated_at` = 2018-08-21 08:22:19 where `user_id` != 27 and `odm_id` = 6 and `priority` = (select MIN(`priority`) where `odm_id` = 6 and `expired` = 0))" – Mohammad_Hosseini Aug 21 '18 at 08:27
  • @Mohammad_Hosseini try adding the table name in the nested select as in the update – apokryfos Aug 21 '18 at 08:28
  • I've already done that but it was giving me this error : "SQLSTATE[HY000]: General error: 1093 You can't specify target table 'orders' for update in FROM clause (SQL: update `orders` set `priority` = 1, `updated_at` = 2018-08-21 08:30:51 where `user_id` != 27 and `odm_id` = 6 and `priority` = (select MIN(`priority`) from `orders` where `odm_id` = 6 and `expired` = 0))" – Mohammad_Hosseini Aug 21 '18 at 08:32
  • Try the update again. It seems that [MySQL is a bit strange in working with the same table in inner queries on updates](https://stackoverflow.com/questions/4429319/you-cant-specify-target-table-for-update-in-from-clause) . – apokryfos Aug 21 '18 at 08:38