Multi Array From Query - php

I am doing a count and sum on each item, and need the array to look like this.
[Date] =>
[device_type1] => [all the data]
[device_type2] => [all the data]
Thing is I am doing a search through each and then all of them return a date, I need all of them to be under that one date, and inside that array to hold each of the devices as key and inside that all the information. here is what I have so far.
$all_device_types = array('pole','covert','firewatch','internet','trailer','slave','project');
foreach ($all_device_types as $adt) {
$du->select("CONCAT(YEAR(uptime_date),'-',MONTH(uptime_date),'-',DAY(uptime_date)) as year_month_day,
SUM(uptime_router) as router,
COUNT(uptime_router) as router_count,
uptime_device_type as device_type,
date(uptime_date) as data_date","
WHERE uptime_device_type = '".$adt."'
GROUP BY CONCAT(YEAR(uptime_date),'-',MONTH(uptime_date),'-',DAY(uptime_date))
ORDER BY uptime_date ASC");
$all_results = array();
while( $all_row = $du->fetch() ){
if ($adt == $all_device_types[0]) {
$dates[] = $all_row['data_date'];
$adt_0 = $all_row;
} elseif ($adt == $all_device_types[1]) {
$adt_1[] = $all_row;
} elseif ($adt == $all_device_types[2]) {
$adt_2[] = $all_row;
} elseif ($adt == $all_device_types[3]) {
$adt_3[] = $all_row;
} elseif ($adt == $all_device_types[4]) {
$adt_4[] = $all_row;
} elseif ($adt == $all_device_types[5]) {
$adt_5[] = $all_row;
} elseif ($adt == $all_device_types[6]) {
$adt_6[] = $all_row;
}
}
}
One of the results looks like this.
[pole] => Array
(
[year_month_day] => 2017-9-5
[router] => 4408
[router_count] => 4620
[device_type] => pole
[data_date] => 2017-09-05
)

It looks like it could be simplified quite a bit. Instead of looping over the device types and running a separate query for each one, you can just add the device type to your GROUP BY and get all your results in a single query.
I think CONCAT(YEAR(uptime_date),'-',MONTH(uptime_date),'-',DAY(uptime_date)) should output the same thing as date(uptime_date), and you should be able to use the aliases in your GROUP BY and ORDER BY clauses.
$du->select("DATE(uptime_date) as data_date,
uptime_device_type as device_type,
SUM(uptime_router) as router,
COUNT(uptime_router) as router_count,
GROUP BY data_date, device_type
ORDER BY data_date, device_type");
If I'm mistaken and you do need the CONCAT version, add it back in of course, but the main thing is adding device_type to the GROUP BY and eliminating the WHERE clause.
Then as you fetch your results, you can insert them directly into the multidimensional structure you want.
while( $row = $du->fetch() ) {
$all_results[$row['data_date']][$row['device_type']][] = $row;
// to calculate totals for all the devices for each date
if (!isset($all_results[$row['data_date']]['all_devices']) {
// initialize if not set
$all_results[$row['data_date']]['all_devices'] = [
'router' => 0, 'router_count' => 0];
}
// increment values
$all_results[$row['data_date']]['all_devices']['router'] += $row['router'];
$all_results[$row['data_date']]['all_devices']['router_count'] += $row['router_count'];
}

Related

How to add an int value to 'i' for each person in a multi-dimensional array every time they satisfy an if statement

I'm trying to create a weighted average based on how well each individual (who has their own array for 'name', 'gender', 'age' 'subject', etc) matches the criteria for the client.
eg.
If they study the right subject, i +100
else if they study a similar subject, i +75
else i * 1.
But I'm aiming for i to be updated for each candidate simultaneously. Feel free to tell me if I'm looking at this the wrong way or there is an easier way of doing this, more than happy to admit mistakes.
I wrote a bit of pseudo code for a simpler version, but I'm concerned that it doesn't fit the specification and would be a bit slow. Code below edited as suggested.
<?php
$sql = "SELECT * FROM data";
$result = mysqli_query($conn, $sql);
$candidates = array();
if (mysqli_num_rows($result) > 0) {
while($row = mysqli_fetch_assoc($result)) {
$candidates[] = $row;
}
}
//Not sure if this next bit makes sense or doing it wrong.
foreach($candidates as $i => $value) {
if (in_array($cand_subject, $searched_subject)) {
$i = $i + 1000;
}
elseif (in_array($cand_subject, $similar_subject)) {
$i = $i + 800;
} else {
$i = $i * 1;
}
You actually want something like this (explained everything in comments)
<?php
$pages_array = array( // intiate an array
array( // another array inside an array to define array of objects.
'name' => 'James',
'skills' => array("ai","php") //another array for array of strings
),
array( // same here
'name' => 'ben',
'skills' => array('C#', 'react', 'flutter')
)
);
foreach ($pages_array as $key => $value) { // for each of the array's
$score = 0;
if (in_array("ai", $value["skills"])) { // note $value["skills"] is an array. So we check if the array has the string "ai"
$score = 100;
}else{
$score = 75;
}
$value["score"] = $score; // add a field score into the array and put the value.
}
?>
This is same as you mentioned the puesdo code in your question.

PHP: If MYSQL Result greater than 0, add to array?

I have a MYSQL table with a list of services that user's provide:
The Enum values in these columns can be 0 or 1.
0 represents a service not offered and 1 represents a service offered.
Cleaning Tour Guide Cooking Parties
0 1 0 1
I am then running the following query In MYSQL to fetch my rows in the table:
<?php $myBio = $conn->query("SELECT * FROM user_data, user_services WHERE user_data.user_id = user_services.user_id AND user_id = $p_id");
if ($myBio->num_rows > 0) {
$row = $myBio->fetch_assoc();?>
I want to generate a list of the services the user provides (where the service has a value greater than 0) - and separate the list with commas like so:
Tour Guide, Parties
I am trying to do this by using an array:
$os = array(if($row['cleaning'] > 0) { echo 'cleaning';}, if($row['tour'] >0) { echo 'Tour Guide'; });
I am trying to use PHP if statements to decipher if a service is 0 or 1 before adding it to my list.
I do not believe it is possible to combine php if statements within an array.
Please can someone show me how I can achieve my desired result? Thanks in advance
Use array_keys() with the optional search parameter:
$services = array_keys($row, 1);
Example:
$row = [
'Cleaning' => 0,
'Tour Guide' => 1,
'Cooking' => 0,
'Parties' => 1,
];
$services = array_keys($row, 1);
var_export($services);
Result:
array (
0 => 'Tour Guide',
1 => 'Parties',
)
Demo
If your database columns have a speaking name, you can do it like this:
<?php
$arrayServices = array();
$arrayAllServices = array('Cleaning','Tour Guide','Cooking','Parties');
foreach($arrayAllServices as $service) {
if($row[$service] > 0) {
$arrayServices[] = $service;
}
}
$sServices = join(', ', $arrayServices);
echo $sServices;
If the speaking names are different from the column names, you need a second array to look up translations.
Would something like this achieve what you want?
$results=array();
if ($row['cleaning']>0) $results[]='Cleaning';
if ($row['tour']>0) $results[]='Tour Guide';
// ...
Also, please heed #tadman's comment about prepared statements!
<?php
$myResults = array();
$myBio = $conn->query("SELECT * FROM user_data, user_services WHERE user_data.user_id = ? AND user_id = ?");
$stmt->bind_param("ss",$user_services.user_id,$p_id);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows === 0) exit('No rows');
while($row = $result->fetch_assoc())
{
$tempArray = array();
$Cleaning = $row['Cleaning'];
$Tour_Guide = $row['TourGuide'];
$Cooking = $row['Cooking'];
$Parties = $row['Parties'];
if($Cleaning == 1)
array_push($tempArray,$Cleaning)
if($Cleaning == 1)
array_push($tempArray,$Cleaning)
if($Cooking == 1)
array_push($tempArray,$Cooking )
if($Parties == 1)
array_push($tempArray,$Parties )
array_push($myResults,$tempArray);
}
?>
You will then get the myResult array which will be an array of arrays, you can then loop over the sub arrays to check values and construct the strings you intend to make.

How can I loop through an array while averaging the values of one element and only keep the newly averaged field in PHP?

I have database that contains scores which are stored daily. I want to average each months scores for each user. So far I have this:
DB structure:
id | name | tscore | added
int| string | float(100 or less)| date(2014-01-01 16:34:22)
Code:
while($row = mysql_fetch_assoc($getChartData)){ // Data from MySQL
$added_date = explode(' ',$row['added']); // Date formate 2014-01-01 16:34:22
$chartData[] = array(
'id' => $row['name'],
'tscore' => $row['tscore'],
'added' => $added_date[0] // Here I take the month only
);
}
if($_POST['range'] == 'month'){
foreach($chartData as $key => $value){
$added = explode('-',$chartData[$key]['added']);
$count = 1;
foreach($chartData as $key2 => $value2){
$added2 = explode('-',$chartData[$key2]['added']);
if($chartData[$key]['id'] === $chartData[$key2]['id'] && $added[1] === $added2[1]){ // if user is the same and the month is the same, add the scores together, increment counter, and unset 2nd instance
$chartData[$key]['tscore'] = ((float)$chartData[$key]['tscore'] + (float)$chartData[$key2]['tscore']);
$count++;
unset($chartData[$key2]);
}
}
$chartData[$key]['tscore'] = ($chartData[$key]['tscore']/$count); // Average all the scores for the month.
}
}
The problem is this method is deleting all the elements of the $chartData array. What can I try to resolve this?
You should try to solve it with MySQL. Try something like this (replace 'your_scores_table' with your table name):
SELECT
Score.name,
AVG(Score.tscore) AS `avg`,
CONCAT(YEAR(Score.added), '-', MONTH(Score.added)) AS `year_month`
FROM
your_scores_table AS Score
GROUP BY
Score.name ASC,
YEAR(Score.added) DESC,
MONTH(Score.added) DESC
;
Your logic is wrong. You are looping through the same array twice. Which means that the following if will always evaluate to true which means that array item will always get unset
//This will always be true
if($chartData[$key]['id'] === $chartData[$key2]['id'] && $added[1] === $added2[1]){
It may be simpler for you to create another array where you keep your scores. Something like
$aScores = array();
$count = 1;
foreach($chartData as $key => $value){
//Add score to a different array
$aScores[$value['name']]['tscore'] = (($aScores[$value['name']]['tscore'] + $value['tscore']) / $count);
$count++;
}
Also I would look into the MySQL AVG function. You could use that to save you having to do it in PHP

Create Array and print it into TXT file

UPDATE:
I get array values from $_POST['changed'].
The array structure looks like this:
Array
(
[0] => Array
(
[recid] => 1
[nachname] => Müller7777
)
[1] => Array
(
[recid] => 3
[vorname] => Maria123
)
)
I get on line #3 this error: Fatal error: Function name must be a string
$uarr=array();
foreach ($_POST['changed'] as $a) {
list($x,$k)=array_keys($a);
list($y,$v)=array_values($a);
$uarr[$y][]="$k='$v'";
}
foreach ($uarr as $k=>$v) {
$sql = "";
$sql .="UPDATE tbl SET ".join(",",$v)." WHERE recid=$k";
// send UPDATE ...
}
file_put_contents('filename2.txt', $sql);
Before I do the final database UPDATE I want to check if the created array does its job. Thats why I want to write the $sql variable first into a txt-file.
------------------------------------------------
SOLUTION:
checking if $_POST['changed'] == null is the final answer for this question.
if ($_POST['changed'] == null) {
} else {
$uarr=array();
$b = $_POST['changed'];
foreach ($b as $a) {
list($x,$k)=array_keys($a);
list($y,$v)=array_values($a);
// $x contains the `recid` key
// $y ... value
$uarr[$y][]="$k='$v'";
}
foreach ($uarr as $k=>$v) {
$sql = "";
$sql .="UPDATE tbl SET ".join(",",$v)." WHERE recid=$k";
// send UPDATE ...
}
file_put_contents('filename2.txt', $sql);
}
Before you run the individual UPDATE statements - yes, for each recid value you should send one statement - you could first collect all the affected values for each recid in an associative array like
$uarr=array();
foreach ($_POST['changed'] as $a) {
list($x,$k)=array_keys($a);
list($y,$v)=array_values($a);
// $x contains the `recid` key
// $y ... value
$uarr[$y][]="$k='$v'";
}
and then do another loop like
foreach ($uarr as $k=>$v) {
$sql="UPDATE tbl SET ".join(",",$v)." WHERE recid=$k";
// send UPDATE ...
}
But, of course, this will only work correctly if the $_POST('changed') array adheres to the described format and order. And, finally, so far there is nothing in this code to protect you from SQL injection.
Try to do it like this:
$BigArray = $_POST['changed'];
$LengthOfArray = sizeof($BigArray);
for ($i = 0; $i < $LengthOfArray ; $i++) {
$SubArray = $BigArray[$i];
// Call the update/insert here
// $SubArray['recid'] is the ID
// $SubArray['vorname'] is the name
}

Trouble with MySQLi and while loops

I have this code here within a class:
function getRolePerms($role)
{
if (is_array($role))
{
$roleSQL = "SELECT * FROM `role_perms` WHERE `roleID` IN (" . implode(",",$role) . ") ORDER BY `ID` ASC";
} else {
$roleSQL = "SELECT * FROM `role_perms` WHERE `roleID` = " . floatval($role) . " ORDER BY `ID` ASC";
}
var_dump($roleSQL);
$this->database->dbquery($roleSQL);
$perms = array();
while($row = $this->database->result->fetch_assoc())
{
$pK = strtolower($this->getPermKeyFromID($row['permID']));
var_dump($pK);
if ($pK == '') { continue; }
if ($row['value'] === '1') {
$hP = true;
} else {
$hP = false;
}
$perms[$pK] = array('perm' => $pK,'inheritted' => true,'value' => $hP,'Name' => $this->getPermNameFromID($row['permID']),'ID' => $row['permID']);
}
return $perms;
}
The var_dump() for $roleSQL is:
SELECT * FROM role_perms WHERE roleID = 1 ORDER BY ID ASC
and for $pK:
Admin
When running the query in the database directly i get a result with 8 rows.
Why is it that the loop does not recognize the multiple rows.
Also if i add the statement:
var_dump($this->database->result->fetch_assoc());
It dumps the array of the first row then the loop does the second row.
Im really baffled,
Please help
The culprit is this line here:
$perms[$pK] = array('perm' => $pK,'inheritted' => true,'value' => $hP,'Name' => $this->getPermNameFromID($row['permID']),'ID' => $row['permID']);
What happens is that all of the 8 rows you expect result in $pK == 'Admin'. When you do $perms[$pK] = array(...), each one of the 8 loop iterations ends up writing to the same array key. In the end, there is only one value in the array.
If you change it to
$perms[] = array(...);
it should work as expected, because each iteration will add a new array element with a unique integer key.
Side note:
Avoid doing this:
$roleSQL = "SELECT * FROM `role_perms` WHERE `roleID` = " . floatval($role) ...
Since roleID surely is an integer, use the right tool for the job: intval($role).
Lol the answer actually lies outside the loop.
Calling this function $this->getPermKeyFromID($row['permID']) actually override the results from the database as it was using the same database object. I fixed it by storing the results in a separate variable local to that loop.

Categories