Laravel update multiple records at once - mysql

I have a mysql database table with 1000000 records. I wanted to update one column in each row.
I tried:
public function methodWorking()
{
$properties = Property::with('requests')->get();
foreach ($properties as $property) {
$property->number_of_request = count($property->requests);
$property->save();
}
}
This one is working but, it's very bad in performance wise.
I wanted to write a code like this:
public function methodExpect()
{
$properties = Property::with('requests')->get();
$property_array = [];
foreach ($properties as $property) {
$property->number_of_request = count($property->requests);
$property_array[] = $property;
}
Property::save($property_array);
}
Is it possible with laravel ?
Thanks.

as I know, No way to do bulk updates in one query with MySQL. You can use something inside a loop like putting Property::save($property_array); inside your foreach.
for more details see this

Changing all (or most) rows often indicates a poor schema design. Would you like to tell us what the column contains and why it needs a mass change?
Consider removing that column from the table -- then provide the value some other way.
Yes, UPDATE of a million row table takes a long time. This is because the old copy of each row is held on to, just in case there needs to be a ROLLBACK.
To chunk the table, doing it in manageable pieces, see http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks

You can use LaravelBatch it's very helpful (tested on 10 000 records )

Related

How select a single row october cms

How to select a single row on october cms?
How can a simple thing be so complicated here?
I thought it would be something to help us and not to disturb something that is as simple as
SELECT * FROM `engegraph_forms_membros`
Here it's like fighting against demons without a bible, oh god why?
Why make the query difficult for newbie?
I understand you don't speak English natively but you should watch every single one of these videos.
Does the record belong to a model in a plugin? Here are the docs on how to work with models.
You make a plugin, set the database which creates models, and then make components to be ran in your CMS Pages.
In a component.php file you can have something like this: Here I am calling the model class Agreements with use Author\Plugin\Models\Agreements;. This allows me to run a function/method to retrieve all agreements or one agreements using laravel's eloquent collection services.
Lets say we have the ID of a record. Well we can either call on the Agreements model with ::find or with ::where. You will noticed I have two functions that essentially do the same thing. ::find uses the primary key of the models (in my case the id) and will return a singular record. *Note that find can take an array and return a collection of records; like ::where. Using ::where we are going to look for the ID. *Note ::where always returns a collection which is why I have included ->first().
<?php namespace Author\Plugin\Components;
use Session;
use Input;
use Crypt;
use Db;
use Redirect;
use Illuminate\Contracts\Encryption\DecryptException;
use October\Rain\Support\Collection;
use Author\Plugin\Models\Agreements;
class GetAgreement extends \Cms\Classes\ComponentBase
{
public function componentDetails()
{
return [
'name' => 'Get one agreement',
'description' => 'Get an agreement to change or delete it'
];
}
public function onRun() {
$this->page['agreement'] = $this->getWithFindAgreement;
}
public function getWithFindAgreement() {
$id = 1;
$agreement = Agreements::find($id);
return $agreement;
}
public function getWithWhereAgreement() {
$id = 1;
$agreement = Agreements::where($id)->first();
return $agreement;
}
}
If for some reason you aren't working with models, here are the docs to work with Databases. You will have to register the use Db; facade.
Here call the table you want and use ::where to query it. *Note the use of ->first() again.
$users = Db::table('users')->get();
$user = $users->where('id', 1)->first();
There are two simple ways to select a single row:
This will give you the'first' record in the selected recordset.
SELECT top 1 * FROM `engegraph_forms_membros`
This will select all the records that meet the predicate requirement that the value of <columnname> is equal to <value>
SELECT * FROM `engegraph_forms_membros` where <columnname>=<value>
If you select a record where multiple values meet that requirement, then you can (randomly) pick one by combining the solutions...
SELECT top 1 * FROM `engegraph_forms_membros` where <columnname>=<value>
But be aware that without an ORDER BY clause, the underlying data is unordered and prone to change uncontrollably, which is why most people (including your boss) will find the use of 'Top' to be improper for real use.

Eliminate data from active dataprovider in Yii2

I'm looking for a way to rotate via data in ActiveDataProvider and erase some rows. I have rather peculiar data structure and I can't get precise data I need with ->andFilterWhere
I know it is possible to use SqlDataProvider but I would prefer to get to know a way to be able to do foreach on every row in ActiveDataProvider and just unset those ones I don't need.
I'm not pasting my code - I use rather simple controller and model generated via Gii - so nothing crazy here.
Will be really glad if anyone could point me into the right direction.
You can do something like this:
$dataProvider = new ActiveDataProvider(['query' => $query]);
foreach ($dataProvider->models as $model) {
//your logic
}
ok, I have found an answer, so I thought I'd share.
To still be able to use active dataprovider and make a funky sql query I want the long way - I prepared a prequery which gave me only id's of rows I wanted and then I passed them into normal search query in ActiveDataProvider's search.
$query->andFilterWhere([
'customer_id' => $tempids,
This way what I got was - I limited the main query only to preselected rows.
You may use getModels() and setModels() to modify list of models available in data provider:
$models = $dataProvider->getModels();
foreach ($models as $index => $model) {
if (/* some condition */) {
unset($models[$index]);
}
}
$dataProvider->setModels($models);
But this is inefficient (you're creating unnecessary models) and will does not work correctly with pagination (you may get less records on page than you want, including edge case with empty page). It is better idea to filter records on query level - if you're able to filter them using SQL, you should be able to do this using ActiveQuery. It should be possible to add most conditions using andWhere(), including handling subquery:
$subquery = (new Query())->from(/* ... */)-> // ... rest of conditions
$dataProvider->query->andWhere(['customer_id' => $subquery]);

Check Value from DBI Query Without Consuming

I have a table in my DB which I just added a new column to, and when I query this table in Perl I want to check only once if this field is empty or not. I need to check the value of this column in just the first row. Usually to go through the query results I use
while (my $row = $sthmm->fetchrow_hashref()) {
# do stuff
}
I could check each row in the while loop but since I only need to do it once, I don't want to waste time doing that.
How can I retrieve one row and check the column's value without consuming it, meaning that I can still go through the whole result in the while loop after checking this condition.
if ( my $row = $sth->fetchrow_hashref() ) {
# Do stuff with first row
do {
# Do stuff to be done to each row
} while $row = $sth->fetchrow_hashref();
}

Updating a single row in TaffyDB

I currently have a database setup within an html page and my requirement is to update a single row within the application.
I could refresh the database with "fresh" data, but that would require too much time.
I had a look at
dbSports().update("aName", object.aname);
However it seems to update all the records in my database instead of just one. Are there any answers to this particular issue?
The Documentation on the matter is missing a major chunk of information, but is covered in a presentation done by the author of the library (http://www.slideshare.net/typicaljoe/better-data-management-using-taffydb-1357773) [Slide 30]
The querying object needs to be pointing to the object you want to update and editing happening from there. i.e.
var obj = dbObject({
Id : value.id
}).update(function() {
this.aName = object.aname;
return this;
});
Where the object in the query points to the ID of the row and the update function then points to it aswell and the callback updates the value that the application needs to update
you first have to find the matching record, then update it
yourDB({"ID":recordID}).update({
"col1":val1,
"col2":val2,
"col3":val3
});

Logical Column in MySQL - How?

I have a datamodel, let's say: invoices (m:n) invoice_items
and currently I store the invoice total, calculated in PHP by totalling invoice_items, in a column in invoices. I don't like storing derived data as it paves the way for errors later.
How can I create a logical column in the invoices table in MySql? Is this something I would be better handling in the PHP (in this case CakePHP)?
There's something called Virtual Fields in CakePHP which allows you to achieve the same result from within your Model instead of relying on support from MySQL. Virtual Fields allow you to "mashup" various data within your model and provide that as an additional column in your record. It's cleaner than the other approaches here...(no afterFind() hacking).
Read more here: http://book.cakephp.org/view/1608/Virtual-fields
Leo,
One thing you could do is to modify the afterFind() method in your model. This would recalculate the total any time you retrieve an invoice (costing runtime processing), but would mean you're not storing it in the invoices table, which is apparently what you want to avoid (correct if I'm wrong).
Try this:
class Invoice extends AppModel {
// .. other stuff
function afterFind() {
parent::afterFind();
$total = 0;
foreach( $this->data['Invoice']['InvoiceItems'] as $item )
$total += ($item['cost'] * $item['quantity']);
$this->data['Invoice']['total'] = $total;
}
}
I may have messed up the arrays on the hasMany relationship (the foreach line), but I hope you get the jist of it. HTH,
Travis
Either you can return the derived one when you want it via
SELECT COUNT(1) as total FROM invoice_items
Or if invoices can be multiple,
//assuming that invoice_items.num is how many there are per row
SELECT SUM(num) as total FROM invoice_items
Or you can use a VIEW, if you have a certain way you want it represented all the time.
http://forge.mysql.com/wiki/MySQL_virtual_columns_preview
It's not implemented yet, but it should be implemented in mysql 6.0
Currently you could create a view.