I have this function that doesn't batch insert to my database, I only used the batch insert function recently because back then I only used object inserts through for loops like this
$subject = ActiveCurriculum::find()
->select('scstock.*')
->joinWith('schead')
->where(['schead.TrNo' => $TrNo])
->one();
$activesubject = new ActiveSubject();
$activesubject->clientid = $clientid;
$activesubject->TrNo = $subject->TrNo;
$activesubject->LINE = $subject->LINE;
$activesubject->period = $subject->schead->period;
$activesubject->subjectcode = $subject->subjectcode;
$activesubject->schedday = $subject->schedday;
$activesubject->schedtime = $subject->schedtime;
//remember to use schead if the value is joined from another table.
$activesubject->section = $subject->schead->section;
$activesubject->roomcode = $subject->roomcode;
$activesubject->units = $subject->units;
$activesubject->save();
//reduces the slot of ccsubject by 1
$subject->slots = $subject->slots - 1;
//never forget the saving part
$subject->save();
I am not able to use this this time because I needed to insert an array of values so as I said I opted to this.
$subjects = ActiveCurriculum::find()
->select(['scstock.*', 'schead.*'])
->leftJoin('schead', 'schead.TrNo = scstock.TrNo')
->where(['sectiongroup' => $group])
->asArray()
->all();
// $activesubject = new ActiveSubject();
$bulkInsertArray = [];
foreach ($subjects as $values) {
$bulkInserArray[] = [
'clientid' => $clientid,
'TrNo' => $values['TrNo'],
'LINE' => $values['LINE'],
'period' => $values['period'],
'subjectcode' => $values['subjectcode'],
'schedday' => $values['schedday'],
'schedtime' => $values['schedtime'],
'section' => $values['section'],
'roomcode' => $values['roomcode'],
'units' => $values['units'],
];
if (count($bulkInsertArray) > 0) {
$columnNameArray = ['clientid', 'TrNo', 'LINE', 'period', 'subjectcode', 'schedday', 'schedtime', 'section', 'roomcode', 'units'];
// below line insert all your record and return number of rows inserted
$insertCount = Yii::$app->db->createCommand()
->batchInsert('subjectcontainer', $columnNameArray, $bulkInsertArray)
->execute();
}
}
But I am not able to
$subject->slots = $subject->slots - 1;
$subject->save();
like in the first one because of the arrays, can you tell me how to do this in my second code because I need to subtract the slots column by 1 every iteration of the for loop this time. Thank you.
You can perform subtraction using single query. Something like this:
$columnToUpdate = ['slots' => new \yii\db\Expression('[[slots]] - 1')];
$condition = ['sectiongroup' => $group];
ActiveCurriculum::updateAll( $columnToUpdate, $condition );
It will execute SQL:
UPDATE `active_curriculum` SET `slots`=`slots` - 1 WHERE `sectiongroup`=1234
You just need to make correct condition that correctly selects necessary rows. Alternatively, you can collect primary keys of records (IDs) when you prepare $bulkInserArray and use them for condition:
$condition = ['id' => $subjectIDsToUpdate];
This condition will build id IN (...) automatically.
Related
I'm trying to pull the last inserted id from a database table so that I can input it into a new database table, like so:
$mealplaninput =
MealPlanInput::create([
'meal_type' => $meal,
'suitable_for' => $suited,
'allergens' => $allerg,
'specific_allergen' => $spec,
'no_of_people' => $nop,
'start_date' => $request->date,
'no_of_days' => $nod,
'user_id' => $currentuserid,
]);
The attempt to pull the last id (but doesn't work):
$uniquemealplanid = $mealplaninput->id();
To then input into new table:
MealPlanDisplay::create([
'MealPlan_ID' => $uniquemealplanid,
'Day' => $recipeday,
]);
However I get the error:
Call to undefined method App\Models\MealPlanInput::id()
I have tried other methods too, like:
$uniquemealplanid = $this->create($mealplaninput)->id;
But the error I get is:
Method App\Http\Controllers\MealPlanInputController::create does not exist.
How can I pull the last id from MealPlanInput?
You need to create an object from the model to get ID.
$mealplaninput = new MealPlanInput;
$mealplaninput->meal_type = $meal;
$mealplaninput->suitable_for = $suited;
$mealplaninput->allergens = $allerg;
$mealplaninput->specific_allergen = $spec;
$mealplaninput->no_of_people = $nop;
$mealplaninput->start_date = $request->date;
$mealplaninput->no_of_days = $nod;
$mealplaninput->user_id = $currentuserid;
$mealplaninput->save();
$uniquemealplanid = $mealplaninput->id;
you need to try
$uniquemealplanid = $mealplaninput->id;
insted of
$uniquemealplanid = $mealplaninput->id();
I want to mass update my records in Laravel but the records not getting updated. I have a different record for each Id. Below is what I am trying.
$ids = [5,6,8,9],
$updated_array = [
['name' => 'tarun'],
['name' => 'Akash'],
['name' => 'Soniya'],
['name' => 'Shalu'],
];
Model::whereIn('id', $ids)->update($updated_array);
Mass updates are used when you're trying to update multiple rows to the same values. You cannot mass update with different values.
Therefore, this would work, but would update all matching records to name of 'tarun':
Model::whereIn('id', $ids)->update(['name' => 'tarun']);
For your example, you could do:
foreach($ids as $key => $id) {
Model::where('id', $id)->update($updated_array[$key]);
}
But as far as I know, there's no way to do this without running 4 queries in Laravel and writing a raw SQL statement to accomplish this would even be messy.
You can use Laravel Upsert for mass update.
For example :
User::query()->upsert([
['id' => 1, 'email' => 'dadan#example.com'],
['id' => 2, 'email' => 'satria#example.com'],
], 'email');
This feature available in Laravel 8 or newer
Some good solutions for this issue are on the following post: https://github.com/laravel/ideas/issues/575
1) Can create custom function to do this, which uses raw SQL, as per barryvdh comment in the post.
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);
}
This apparently increase performance by 13x
2) As per another comment, another idea is to do it on a per record basis, but do the whole thing as a single transaction, which makes it much faster.
DB::beginTransaction();
// your loop and updates;
if( !$user )
{
rollbackTransaction();
} else {
// Else commit the queries
commitTransaction();
}
3) There is a laravel library also that appears to try and solve this issue. https://github.com/mavinoo/laravelBatch
Note: I have not tried or tested any of the above solutions.
I think the only way to do this without n queries would be to
(optional) backup table
grab the records and create an array with all the updated data
bulk delete the records
bulk insert from array
That's 3 queries.
Iterating through n records is not practical for my application either; I was hoping there was an alternative but it looks like I'm going to have to implement this.
We can Insert and update batch (bulk) in laravel using this Package
Laravel Batch
Please try the below code:
$data_to_be_updated = [ ['id'=>5,'name' => 'tarun'], ['id'=>6, 'name' => 'Akash'],
['id'=>8, 'name' => 'Soniya'], ['id'=>9,'name' => 'Shalu']
];
foreach ($data_to_be_updated as $key => $value) {
$data = Model::where('id',$value['id'])->first();
if ($data) {
$data->name = $value['name'];
$data->save();
}
}
you can do it like this above mentioned:-
foreach($ids as $key => $id) {
Model::where('id', $id)->update($updated_array[$key]);
}
I am inserting data to payments table where Ref column needs to be unique. In below code, with $ref=$_POST['PAYMENT_ID']; I am inserting always a new ref no with other column value in each post back. Sometimes it is posting duplicate ref no. I am trying to keep the ref no unique.
For this I have written following code.What I am trying to do is if existing Ref Column value doesn't match with new $ref=$_POST['PAYMENT_ID'] value then it will insert data.But it is not working and inserting ref no yet it is matched with new ref no.
How can I do this?
<?php
$ref=$_POST['PAYMENT_ID'];
$pending = "Pending";
$method = "Uploaded funds";
$today = date('Y-m-d');
$time=$_POST['TIMESTAMPGMT'];
$type = "Pm";
$table_payments = $wpdb->prefix . "payments";
$check=$wpdb->get_results("SELECT Ref FROM $table_payments");
$checkrows=mysqli_num_rows($check);
if ($checkrows!=$ref) {
if($hash2==$_POST['V2_HASH']){
$wpdb->insert( $table_payments, array(
'Method' => $method,
'Today' => $today,
'Time' => $time,
'Ref' => $ref,
'Batch' => $batch,
'Type' => $type,
'Status' => $pending,
'User' => $me
));}}
?>
The problem is, $Ref is a user's submitted value and $checkrows holds the total number of rows in $table_payments table. And that's why the condition if ($checkrows!=$ref) { ... is failing.
You have to change your SQL query and the subsequent code in the following way,
// your code
$table_payments = $wpdb->prefix . "payments";
$check=$wpdb->get_results("SELECT * FROM $table_payments WHERE Ref = '$ref'");
$checkrows=$wpdb->num_rows;
if ($checkrows == 0) {
// do INSERT operation
}
Moreover, you should make Ref column of your table unique
This is my function to insert new rows to a table, depending on the date. I want to avoid duplication of rows if one already exists. This function basically inserts November, 2014 as mwf_month, so mwf_student_id and mwf_month pairs are unique for the row. What modification should I do to avoid this kind of duplication?
public function month_wise_due($grade_due, $new_due, $id, $remaining) {
$now1 = time();
$now = date('F, Y', $now1);
$store = array(
'mwf_month' => $now,
'mwf_previous' => $remaining,
'mwf_due' => $grade_due,
'total_due' => $new_due,
'mwf_student_id' => $id,
'mwf_pay_day' => 'Not Yet Paid',
'mwf_payment' => 0,
'mwf_diff' => $new_due
);
$this->db->trans_start();
$this->db->insert('mwf', $store);
$this->db->trans_complete();
}
The right way is to update your database table by adding "unique key" on two fields "mwf_month+mwf_student_id". The SQL command to do it is:
ALTER TABLE `mwf` ADD UNIQUE `unique_month_student`(mwf_month,mwf_student_id);
Then, possible duplicity would end with SQL error you can catch. You can also suppress the exception with 'ignore' statement or use 'replace' method instead of 'insert'.
If you don't have needed privileges on the table, you would need to simply check whether the pair exist with separate sql call before inserting new record.
I have found a solution from some where else without altering the table, it seems good to me.
$now1 = time();
$now = date('F, Y', $now1);
$row_exists = "SELECT * FROM mwf WHERE mwf_month = '" . $now."' AND mwf_student_id = '" . $id."' LIMIT 1";
if ( ! $this->db->simple_query($row_exists)) {
$store = array(
'mwf_month' => $now,
'mwf_previous' => $remaining,
'mwf_due' => $grade_due,
'total_due' => $new_due,
'mwf_student_id' => $id,
'mwf_pay_day' => 'Not Yet Paid',
'mwf_payment' => 0,
'mwf_diff' => $new_due
);
$this->db->trans_start();
$this->db->insert('mwf', $store);
$this->db->trans_complete();
}
Here is the code:
$the_question = $_POST['question'];
$the_answer = $_POST['answer'];
$dummy_num[] = $_POST['dummy_answer_1'];
$dummy_num[] = $_POST['dummy_answer_2'];
$dummy_num[] = $_POST['dummy_answer_3'];
//Get Hidden Test ID and Q_order
$test_id = $_POST['test_id'];
$q_order = $_POST['q_order'];
//Submit Question
$data_submit_q = array (
'type' => 1,
'question' => $the_question,
'done' => 1
);
$this->db->where('test_id', $test_id);
$this->db->where('q_order', $q_order);
$this->db->update('questions', $data_submit_q);
$question_id = $this->db->insert_id();
$time_created = date('Y-m-d H:i:s');
//Submit Answer
$data_submit_a = array (
'test_id' => $test_id,
'question_id' => $question_id,
'option' => $the_answer,
'company_id' => $data['company']->id,
'job_id' => $data['session_job_id'],
'time_created' => $time_created
);
$this->db->insert('options', $data_submit_a);
$answer_id = $this->db->insert_id();
//Let question know that answer is right.
$data_submit_qr = array (
'answer_id' => $answer_id
);
$this->db->where('id', $question_id);
$this->db->where('test_id', $test_id);
$this->db->update('questions', $data_submit_qr);
Setting the answer id removes the value of the question id, then on updating the database the answer id has no value also. Even though it does right before.
The method $this->db->insert_id() retrieves the ID when performing database inserts (as the name hints).
You're using it after an update, that's why your $question_id gives problems (I think it would be set to FALSE, but I don't know for sure what does that method return when called on the wrong context). WHen you do your last update you use this as a WHERE condition, and if it is not set...
It's not that your second call to insert_id() wipes out the first, I suspect is more like the first one is already NOT SET (or FALSE)
It seems that there is a bug with insert_id, you can try using:
$query = $this->db->query('SELECT LAST_INSERT_ID()');
$row = $query->row_array();
$lastInsertId = $row['LAST_INSERT_ID()'];
Hope it helps