Sums data from an array that has the same id - php

I have a query about this project that I am doing, I make a query to my two tables and the data that I call in this case is a quantity number for both, the data displayed is the one that has the same id for both tables.
The problem occurs when I pass two identifiers and to those two identifiers I want to add their current amount with the amount obtained from the other table
In general, what I want to do is add the amounts obtained, this is my code that I am working with, I would really appreciate if you can help me solve it or guide me.
$id_servis = [1077,1078];
$sum_quantity_add = Servis_tareas::where('servis_id',$id_servis)->get();
foreach($sum_quantity_add as $sum_add){
$quantity_two[] = $sum_add->quantity;
}
$quantity_actual = Servis::wherein('id',$id_servis)->get();
foreach($quantity_actual as $quantity_act){
$quantity_one[] = $quantity_act->quantity_final;
}
dd($id_servicios,$quantity_one, $quantity_two);
//ERROR
$total[] = $quantity_one + $quantity_two;
//ERROR
if(is_numeric($total) < 0 ){
Servis::wherein('id',$id_servis)->update(['quantity_final' => 0]);
}else{
Servis::wherein('id',$id_servis)->update(['quantity_final' => $total]);
}

In MySql/SQL there is SUM query which handles the addition and they are called Aggregation Functions, and in Laravel there is a Eloquent equivalent of these Laravel Aggregates, using these methods you will be able to count, max, min, avg on the query end rather than in the PHP end.
So, your code will look like
$id_servis = [1077, 1078];
$sum_quantity_add = Servis_tareas::where('servis_id', $id_servis)->SUM('quantity');
$quantity_actual = Servis::wherein('id', $id_servis)->SUM('quantity_final');
$total = $sum_quantity_add + $quantity_actual;
What you are trying is treating array as numeric value and adding it, which is wrong, + operator behaves totally different while you are using with array, it merges the two array, it is different than array_merge too, so i recommend giving this answer a read + operator for array in PHP
UPDATED:
I still don't understand if you want to replace with the SUM from Servis_tareas in the Servis Table or sum the each others quantity and save it, Code below sum the data from both table and save it.
$id_servis = [1077, 1078];
$servisTareas = Servis_tareas::selectRaw("SUM(`quantity`) as total, `servis_id` ")
->where('servis_id', $id_servis)
->groupBy('servis_id')
->having('total', '>', 0)
->get();
$foundId = [];
$servisTotal = Servis::query()->whereIn('id', $id_servis)->pluck('quantity_final', 'id')->toArray();
foreach ($servisTareas as $servisTarea) {
$foundId[] = $servisTarea->servis_id;
$total = $servisTarea->total + ($servisTotal[$servisTarea->servis_id] ?? 0)
Servis::where('id', $servisTarea->servis_id)->update(['quantity' => $total]);
}
if (!empty($foundId)) {
Servis::whereNotIn('id', $foundId)->update(['quantity' => 0]);
}

Related

How do I place in order 3,4 and 5 values based on amount (high-low) php

I started writing this code to determine which value within 3 date of births was the highest. As I got to as far as you can see I realised this was a silly way of doing it. There will at times be 4 values or even 5 values so writing every combination like this is sloppy.
$new_date_year1 etc are pre defined from a html form.
Can someone recommend another way of doing this.
$valuename1 = "Tom";
$valuename2 = "Jack";
$valuename3 = "Fred";
if ($amount == "3") {
if ($new_date_year1 > $new_date_year2 and $new_date_year1 > $new_date_year3 and $new_date_year2 > $new_date_year3) {
$highest_amount = $valuename1;
$second_amount = $valuename2;
$third_amount = $valuename3;
}
else if ($new_date_year1 > $new_date_year2 and $new_date_year1 > $new_date_year3 and $new_date_year3 > $new_date_year2) {
$highest_amount = $valuename1;
$second_amount = $valuename3;
$third_amount = $valuename2;
}
}
Thanks is advance for any help
just in html form replace variable names from $new_date_year1 into $new_date_year[] etc.
then in php You will have array that is sortable, so:
$new_date_year[] = '2015';
$new_date_year[] = '2018';
$new_date_year[] = '2016';
You can insert data to the array in this way as well(using array_push):
// implementing an empty array.
$new_date_year = [];
//using array_push
//you can pass multiple values to the array for explain it further i will pass '2015','2016','2018' to the array.
array_push($new_date_year,'2015','2016','2018');
After adding the values to the array you can sort the array using rsort which ,
sorts an array in reverse order (highest to lowest).
rsort($new_date_year);
$highest_amount = $new_date_year[0];
$second_amount = $new_date_year[1];
$third_amount = $new_date_year[2];

PHP - Laravel - Getting average directly from Eloquent and not having to loop through the results

I'm building a survey platform and I need to get the average answer rate of the survey.
What I'm currently doing is retrieving all the questions and then dividing times viewed and times answered. Is there a more efficient / less resource consuming method by calculating average on the DB and not looping through thousands of results?
Here is my working code right now that takes forever:
$total_showed = 0;
$total_answered = 0;
$total_queries = Query::where('client_app_id','=', $app_id)->get();
foreach ($total_queries as $app_query) {
$total_showed = $total_showed + $app_query->showed;
$total_answered = $total_answered + $app_query->answered;
}
if ($total_showed > 0) {
$total_arate = round(($total_answered / $total_showed) * 100, 1);
} else {
$total_arate = 0;
}
try
$total_showed = $total_queries->sum('showed')
$total_answered = $total_queries->sum('answered')
since $total_queries is a collection you can use it's sum method
see https://laravel.com/docs/5.3/collections#method-sum
this would be mre efficient I think
Sure you can go into Raw SQL:
instead of:
$total_queries = Query::where('client_app_id','=', $app_id)->get();
use something like:
$total_queries = Query::select(DB::raw('SUM(showed) as counter, SUM(answered) as answered'))
->where('client_app_id','=', $app_id)->get();
try this aggregate function avg(); like this
$price = DB::table('orders')->where('finalized', 1)
->avg('price')

Can you query an array? Laravel 5.2

Maybe a silly question here, but I am working on an app where we need to calculate some basic demographic stats. I want to make a trip to the data base once and then try and query that array of Eloquent models. Right now I am getting an array using the query, and then looping through it to count some stats.
i.e.
$people = Person::all();
$total = count($people);
$count = 0;
foreach($people as $person)
if($person->age > 60) {
count++;
}
}
$percent = $count/$total;
Which works but we have to do this for hundreds of data points.
Can I do something like this?
i.e.
$people = Person::all();
$total = count($people);
$count = $people->where('age', '>=', '60')->count();
$percent = $count/$total;
My thought is that the latter will be more efficient (if possible) because it only makes one trip to the database and doing the aggregate stuff on server side? Or would it be better to make multiple queries and get the database to do all the aggregate stuff?
Thanks,
Matt
You want Collections.
https://laravel.com/docs/5.2/collections
Collections in Laravel are handy Array wrappers that provide additional logic that is very similar to the ODB structure. In fact, when you get Eloquent results, you get a special Database collections.
https://laravel.com/api/5.1/Illuminate/Support/Collection.html
https://laravel.com/api/5.1/Illuminate/Database/Eloquent/Collection.html
You can use a variety of logic on both of these object types that are basically identical to Builders for Eloquent DB queries.
Yes you can, Eloquent has an aggregate count method, try this:
$total = Person::count();
$count = Person::where('age', '>=', '60')->count();
$percent = $count/$total;
It would be more efficient to query the database once, and then filter the resulting collection:
$people = Person::all();
$total = count($people);
$peopleOver60 = $people->filter(function($item) {
return $item->age >= 60;
});
$percent = count($peopleOver60) / $total;
Yes is great for performance
and You can change your code like that :$people to Person::
$people = Person::all();
$total = count($people);
$count = Person::where('age', '>=', '60')->count();
$percent = $count/$total;
Your database optimized for searching queries but PHP isn't. You should use your "where" queries in DB. But if you want it anyway you can check this library :
https://phplinq.codeplex.com/

php "count()" function and DB

I have a Joomla 1.5 site. I have articles in my site with different "status". What I'm trying to do is "count" and show how many articles have for example "status = 1"(expired) or "status = 3"(blocked) or "status = 2"(active) etc..
Here is the statuses in PhpMyAdmin - http://awesomescreenshot.com/07a8ijz75
Here is what I wrote, but it ALWAYS gives me same result - 1
<?php echo count($this->row->status==1) ?>
Did I miss something?
Thanks
Use the SQL count function.
select count(*) from articles where status = 1;
Use your DB! If you are sorting, counting, etc, data from a database in PHP code you're doing it wrong.
If you want all statuses, do something like:
select status, count(*) from articles group by status;
The count function in PHP counts all the elements in an array, and in your example you passed it a boolean value. As a result count doesn't know what to do with it, and so it returns -1, which isn't a valid count.
My PHP is really rusty (I haven't used it in a looong time), but here are two possible ways to accomplish what you want:
1. Use a function map/reduce style
<?php
$row[0]->status = 1;
$row[1]->status = 2;
$row[2]->status = 1;
$row[3]->status = 3;
$row[4]->status = 1;
// Count the number of statuses that are equal to 1
echo array_reduce(array_map(function($x) {
return $x->status == 1 ? 1: 0;
}, $row), function($x, $y) {return $x + $y;});
You'll have to replace the $row variable with $this->row, obviously. The code is essentially working in two steps. The inner part:
array_map(function($x) {
return $x->status == 1 ? 1: 0;
}, $row)
Creates a list where every status that's equal to 1 becomes a 1 and everything else becomes a 0. So you have an array of "array(1, 0, 1, 0, 1)". The out part of the code:
array_reduce( ... , function($x, $y) {return $x + $y;});
Takes the new array as the first argument and sums it all up by passing in the first two values of the array into the function, and then each following value and the result of the last function call. As a result all the values get summed, and you have a proper count of the matching values.
2. Use a simple procedural style
<?php
$row[0]->status = 1;
$row[1]->status = 2;
$row[2]->status = 1;
$row[3]->status = 3;
$row[4]->status = 1;
// Do it again, but in a procedural style
$num_1_statuses = 0;
foreach ($row as $r) {
if ($r->status == 1) {
$num_1_statuses++;
}
}
echo $num_1_statuses;
This should be really straightforward, it just has a variable that gets incremented whenever a row's status matches.

How can I select a PHP variable that relates to a specific percentage chance?

I'm trying hard to wrap my head around what I'm doing here, but having some difficulty... Any help or direction would be greatly appreciated.
So I have some values in a table I've extracted according to an array (brilliantly named $array) I've predefined. This is how I did it:
foreach ($array as $value) {
$query = "SELECT * FROM b_table WHERE levelname='$value'";
$result = runquery($query);
$num = mysql_numrows($result);
$i=0;
while ($i < 1) {
$evochance=#mysql_result($result,$i,"evochance"); // These values are integers that will add up to 100. So in one example, $evochance would be 60, 15 and 25 if there were 3 values for the 3 $value that were returned.
$i++;
}
Now I can't figure out where to go from here. $evochance represent percentage chances that are linked to each $value.
Say the the favourable 60% one is selected via some function, it will then insert the $value it's linked with into a different table.
I know it won't help, but the most I came up with was:
if (mt_rand(1,100)<$evochance) {
$valid = "True";
}
else {
$valid = "False";
}
echo "$value chance: $evochance ($valid)<br />\n"; // Added just to see the output.
Well this is obviously not what I'm looking for. And I can't really have a dynamic amount of percentages with this method. Plus, this sometimes outputs a False on both and other times a True on both.
So, I'm an amateur learning the ropes and I've had a go at it. Any direction is welcome.
Thanks =)
**Edit 3 (cleaned up):
#cdburgess I'm sorry for my weak explanations; I'm in the process of trying to grasp this too. Hope you can make sense of it.
Example of what's in my array: $array = array('one', 'two', 'three')
Well let's say there are 3 values in $array like above (Though it won't always be 3 every time this script is run). I'm grabbing all records from a table that contain those values in a specific field (called 'levelname'). Since those values are unique to each record, it will only ever pull as many records as there are values. Now each record in that table has a field called evochance. Within that field is a single number between 1 and 100. The 3 records that I queried earlier (Within a foreach ()) will have evochance numbers that sum up to 100. The function I need decides which record I will use based on the 'evochance' number it contains. If it's 99, then I want that to be used 99% of the time this script is run.
HOWEVER... I don't want a simple weighted chance function for a single number. I want it to select which percentage = true out of n percentages (when n = the number of values in the array). This way, the percentage that returns as true will relate to the levelname so that I can select it (Or at least that's what I'm trying to do).
Also, for clarification: The record that's selected will contain unique information in one of its fields (This is one of the unique values from $array that I queried the table with earlier). I then want to UPDATE another table (a_table) with that value.
So you see, the only thing I can't wrap my head around is the percentage chance selection function... It's quite complicated to me, and I might be going about it in a really round-about way, so if there's an alternative way, I'd surely give it a try.
To the answer I've received: I'm giving that a go now and seeing what I can do. Thanks for your input =)**
I think I understand what you are asking. If I understand correctly, the "percentage chance" is how often the record should be selected. In order to determine that, you must actually track when a record is selected by incrementing a value each time the record is used. There is nothing "random" about what you are doing, so a mt_rand() or rand() function is not in order.
Here is what I suggest, if I understood correctly. I will simplify the code for readability:
<?php
$value = 'one'; // this can be turned into an array and looped through
$query1 = "SELECT sum(times_chosen) FROM `b_table` WHERE `levelname` = '$value'";
$count = /* result from $query1 */
$count = $count + 1; // increment the value for this selection
// get the list of items by order of percentage chance highest to lowest
$query2 = "SELECT id, percentage_chance, times_chosen, name FROM `b_table` WHERE `levelname` = '$value' ORDER BY percentage_chance DESC";
$records = /* results from query 2 */
// percentage_chance INT (.01 to 1) 10% to 100%
foreach($records as $row) {
if(ceil($row['percentage_chance'] * $count) > $row['times_chosen']) {
// chose this record to use and increment times_chosen
$selected_record = $row['name'];
$update_query = "UPDATE `b_table` SET times_chosen = times_chosen + 1 WHERE id = $row['id']";
/* run query against DB */
// exit foreach (stop processing records because the selection is made)
break 1;
}
}
// check here to make sure a record was selected, if not, then take record 1 and use it but
// don't forget to increment times_chosen
?>
This should explain itself, but in a nutshell, you are telling the routine to order the database records by the percentage chance highest chance first. Then, if percentage chance is greater than total, skip it and go to the next record.
UPDATE: So, given this set of records:
$records = array(
1 => array(
'id' => 1001, 'percentage_chance' => .67, 'name' => 'Function A', 'times_chosen' => 0,
),
2 => array(
'id' => 1002, 'percentage_chance' => .21, 'name' => 'Function A', 'times_chosen' => 0,
),
3 => array(
'id' => 1003, 'percentage_chance' => .12, 'name' => 'Function A', 'times_chosen' => 0,
)
);
Record 1 will be chosen 67% of the time, record 2 21% of the time, and record 3 12% of the time.
$sum = 0;
$choice = mt_rand(1,100);
foreach ($array as $item) {
$sum += chance($item); // The weight of choosing this item
if ($sum >= $choice) {
// This is the item we have selected
}
}
If I read you right, you want to select one of the items from the array, with some probability of each one being chosen. This method will do that. Make sure the probabilities sum to 100.

Categories