I have a project written using PHP on the top of Laravel 5.7. I am using Eloquent ORM to interact with the database.
I need to be able to update lots of records after pulling them from the database.
Here is how I am trying to do it.
$records = Record::where('Key','Test')->get();
$values = collecT([
['Id' => 1, 'Col' => 100],
['Id' => 2, 'Col' => 200],
['Id' => 3, 'Col' => 500],
....
]);
foreach($records as $record) {
$newValue = $values->where('Id', $record->id)->first();
if(is_null($newValue)){
continue;
}
$record->ColName = $newValue['Col'];
$record->save();
}
The above code does not write the updated value to the database. However, if I do the following it gets updated
foreach($values as $value) {
$record = Record::where('Key','Test')->where('id', $value['Id'])->first();
if(is_null($record)){
continue;
}
$record->ColName = $value['Col'];
$record->save();
}
Although the above code works, I have to make 1 select + 1 update statement for every record in the $values array. If the size of $values array is 1000. That's going to generate up to 2000 queries which are insane!
How can I correctly update multiple records in the database without doing range-update.
If all the rows you are trying to update would get the same value it is an easy problem. The problem becomes a bit more tricky because all your rows need to be updated with different values. This comment on a github issue of laravel has a solution that will do it with a single query, allowing him in that case with a 13x performance boost for 1000 rows to be updated compared to updating them one by one:
public static function updateValues(array $values)
{
$table = MyModel::getModel()->getTable();
$cases = [];
$ids = [];
$params = [];
foreach ($values as $id => $value) {
$id = (int) $id;
$cases[] = "WHEN {$id} then ?";
$params[] = $value;
$ids[] = $id;
}
$ids = implode(',', $ids);
$cases = implode(' ', $cases);
$params[] = Carbon::now();
return \DB::update("UPDATE `{$table}` SET `value` = CASE `id` {$cases} END, `updated_at` = ? WHERE `id` in ({$ids})", $params);
}
You can also try https://github.com/mavinoo/laravelBatch which does something similar.
Related
I have a sensor list form in my program. There the user can do CRUD.
How do when the user enters new sensor data, the new data automatically creates a new column in the table in my database (automatically alter table)
public function store(Request $request){
$data = new Mst_sensor();
$arr = array_merge($arr, ['created_by' => Auth::user()->userid, 'created_at' => date('Y-m-d H:i:s')]);
$data->create($arr);
$sensor= new Trs_sensor_d;
$table = $sensor->getTable();
$columns = \DB::getSchemaBuilder()->getColumnListing($table);
$data_field = [];
foreach ($columns as $k => $v) {
$data_field[$k] = $v;
}
$removed = array_pop($data_field);
$fix_data_field = end($data_field);
$q = "ALTER TABLE `trs_raw_d_gpa` ADD `coba` VARCHAR(25) NULL AFTER '" . $fix_data_field . "'";
}
How can alter table run automatically???
Think about how to design the database so that users cannot change the structure.
What you want to do is not recommended.
I'm using Laravel 6 and Eloquent. I'm looking for a way to update a set of rows with a set value, each identified with a unique ID.
This is what I'm doing right now:
$ids = [3948, 1984, 7849, 4456, 394];
$value = false;
foreach ($ids as $id)
{
User::where("id", $id)->update(["status" => $value]);
}
Is there a way to accomplish the same with only 1 query instead of 5?
You can use whereIn, like:
$ids = [3948, 1984, 7849, 4456, 394];
$value = false;
User::whereIn("id", $ids)->update(["status" => $value]);
In Laravel 4.2, I have the following code:
$thingIds = [];
foreach ($this->things as $thing) {
$thingIds[] = $thing->id;
}
$thong->things()->sync($thingIds);
$thong->save();
Which seems to work for me, however in my pivot table I have an order column that isnt being updated/synced correctly. The order is set to 1 for each item in the pivot table, however I want the order to be representative of the order of the ids in $thingIds.
Is this possible?
Is it possible to update an additional column in the pivot table using ->sync()?
After the suggestion in the comments, I have also tried the following code:
$thingIds = [];
foreach ($this->things as $index => $thing) {
$thingIds[$thing->id] = ['order' => $index];
}
$thong->things()->sync($thingIds);
$thong->save();
And I have tried
$thingIds = [];
$order = [];
foreach ($this->things as $index => $thing) {
$thingIds[] = $thing->id;
$order[] = ['order' => $index];
}
$thong->things()->sync(array_combine($thingIds, $order));
$thong->save();
But neither of these is working (the order is still 1 for each item in the pivot table). Can anyone explain what I am doing wrong?
If I do the attaching one at a time, like so:
foreach ($this->things as $index => $thing) {
$thong->things()->attach($thing, ['order' => $index]);
}
The order comes out correctly in the pivot table. How can I get the same effect but whilst still using ->sync()?
Its an online result marker. Once the user clicks save it gets the CA(Continious assessment) and it gets the Exam marks and the teachers remark for the particular student. I want to know how i can insert these fields into my database the right way.
return $request->all();
the above code returns the image below
$i = 0;
foreach($request->id as $id) {
$model = new Model;
$model->user_id = $id;
$model->ca_mark = $request->ca_mark[$i];
$model->exam_mark = $request->ca_mark[$i];
$model->remarks = $request->remarks[$i];
$model->save();
$i++;
}
Query Builder
$i = 0;
foreach($request->id as $id) {
DB::table('table')->insert([
'user_id' => $id,
'ca_mark' => $request->ca_mark[$i],
'exam_mark' => $request->ca_mark[$i],
'remarks' => $request->remarks[$i]
]);
$i++;
}
The above code has been written based on an assumption of the database table structure. In short, foreach on the ID's as this would be the student ID, and take the ca_mark, exam_mark and remark based on the key of the id.
I have code like this:
$id = 5;
$a = 1;
$b = ($a === 2 ? 1 : 2);
DB::table('table')->where('id', $id)->where('value', $a)->update(['new_value' => 1]);
DB::table('table')->where('id', $id)->where('value', $b)->update(['new_value' => 2]);
Is it possible to make this 2 queries in 1?
You cannot use the query builder for this. Use DB::statement instead:
DB::statement('UPDATE table SET new_value = CASE
WHEN value = ? THEN ?
WHEN value = ? THEN ?
END WHERE id = ?', [
$a, 1,
$b, 2,
$id,
]);
In mysql query you can achieve by below query:
$mysqlQuery = "UPDATE table1
SET new_value = IF(id=".$id ." AND value=".$a.",1, IF(id=".$id." AND value=".$b.",2,new_value))";
Note:If you want this mysql query to be written in some framework specific query then you can convert it as per your framework syntax or documentation.
AFAIK, not with laravel fluent. There are 2 different queries with different update values. You can however make it into a reusable function.
public function updateNewValue($id, $value, $newValue)
{
return DB::table('table')
->where('id', $id)
->where('value', $value)
->update(['new_value' => $newValue]);
}
Or, you can combine it into one with a switch statement depending on the new_value:
$query = DB::table('table')->where('id', $id);
switch($newValue)
{
case 1:
return $query->where('value', $a)->update(['new_value' => $newValue]);
case 2:
return $query->where('value', $b)->update(['new_value' => $newValue]);
}