I have this PHP code, with a for loop:
$expireData = array();
for($x = 0; $x <= 10; $x++){
$stmt=$dbh->prepare("select round((expire - unix_timestamp()) / 86400) as days, count(*) as cnt from users WHERE user_by=:username group by days;");
$stmt->bindParam(":username",$userdata['username']);
$stmt->execute();
$row = $stmt->fetchAll();
#var_dump($row);
if($row["cnt"] > 0){
$expireData[] = $row["cnt"];
}else{
$expireData[] = 0;
}
}
If I do the var_dump($row) I get:
array(2) {
[0]=>
array(4) {
["days"]=>
string(2) "27"
[0]=>
string(2) "27"
["cnt"]=>
string(1) "2"
[1]=>
string(1) "2"
}
[1]=>
array(4) {
["days"]=>
string(3) "116"
[0]=>
string(3) "116"
["cnt"]=>
string(1) "8"
[1]=>
string(1) "8"
}
}
But if I just echo $row['cnt']; it doesn't echo anything out - it's empty. Why?
Ultimately, I wish to use the data from the for loop outside the for loop - like:
echo implode(',', $expireData);
But that just gives me
0,0,0,0,0,0,0,0,0,0
What am I doing wrong?
Because you're using fetchAll() to retrieve all rows into $row, its contents are a 2 dimensional array representing multiple rows. So the key ['cnt'] is present, but is one dimension farther in your array.
$row['cnt'] doesn't exist but $row[0]['cnt'] does and $row[1]['cnt'] do exist.
The simplest solution with your current code is to move the $expireData handling outside the loop and into a loop of its own:
$expireData = array();
$stmt=$dbh->prepare("select round((expire - unix_timestamp()) / 86400) as days, count(*) as cnt from users WHERE user_by=:username group by days;");
$stmt->bindParam(":username",$userdata['username']);
$stmt->execute();
// Load all rows into $rows rather than $row...
$rows = $stmt->fetchAll();
// Loop over all rows to populate $expireData
foreach ($rows as $row) {
if ($row["cnt"] > 0){
$expireData[] = $row["cnt"];
}else{
$expireData[] = 0;
}
}
print_r($expireData);
The other method would be to switch from fetchAll() to plain fetch() and append rows onto $rows in a while loop:
// Array to hold all rows
$rows = array();
// (The outer for loop is removed...)
$stmt=$dbh->prepare("select round((expire - unix_timestamp()) / 86400) as days, count(*) as cnt from users WHERE user_by=:username group by days;");
$stmt->bindParam(":username",$userdata['username']);
$stmt->execute();
// Perform single fetch() calls in a while loop
while ($row = $stmt->fetch()) {
// Append onto array of all rows
$rows[] = $row;
// Then handle $expireData in the same loop
if ($row["cnt"] > 0){
$expireData[] = $row["cnt"];
}else{
$expireData[] = 0;
}
}
Pad the array to 10 values:
As determined in the comments, you need your final $expireData array to have 10 values. Rather than doing that with a loop, use array_pad() to extend it to ten and fill it with zeros.
$expireData = array_pad($expireData, 10, 0);
// turns [2,8] into [2,8,0,0,0,0,0,0,0,0]
Notes on the for loop:
The use of the outer for look is suspect because it is apparently executing the same statement each time. That loop may be entirely unneeded, and all you need is its body.
Notes on error reporting:
The fact that you did not see PHP complaining about undefined index 'cnt' while loading the loop suggests that you are not developing with display_errors turned on and error_reporting turned up. Always do so when developing and testing code. It may have helped you see the problem sooner.
At the top of your script:
error_reporting(E_ALL);
ini_set('display_errors', 1);
Related
I am doing the following queries on a database that holds various customers orders.
SELECT WEEKDAY(orderDateTime) Date, COUNT(clientID) totalCount FROM orders WHERE YEARWEEK(orderDateTime,1) = YEARWEEK(NOW(),1) GROUP BY DATE(orderDateTime)
SELECT WEEKDAY(orderDateTime) Date, COUNT(clientID) totalCount FROM orders WHERE YEARWEEK(orderDateTime,1) = YEARWEEK(NOW() - INTERVAL 1 WEEK,1) GROUP BY DATE(orderDateTime)
SELECT DATE_FORMAT(orderDateTime, '%Y') as 'year', DATE_FORMAT(orderDateTime, '%m') as 'month', COUNT(clientID) as 'total' FROM orders GROUP BY DATE_FORMAT(orderDateTime, '%Y%m')
I am them building these into an array with the month/ day numbers against the counted value:
[[0, 1], [1,4]...]
I am using Flot to graph these but what is happening is that any days or months that there are no orders it has no values (Obviously) so what you get is something like this:
[[0, 1], [1,4], [6,12]] which makes the graph plot wrong.
What trying to work out is how to pad it so it looks like:
[[0, 1], [1,4], [2,0], [3,0], [4,0], [5,0], [6,12]] <-- For the week days and,
[[1, 1], [2,4], [3,0], [4,0], [5,0], [6,0], [7,12], [8,0], [9,12], [10,0], [11,0], [12,0]] <-- for each month.
Im using PHP as the main grunt. Any pointers would be appreciated and sorry if I'm not that clear. Ask if you need any clarification.
PHP:
$thisWeekA = array();
$thisWeekQ = $database->query("SELECT WEEKDAY(orderDateTime) Date, COUNT(clientID) totalCount FROM orders WHERE YEARWEEK(orderDateTime,1) = YEARWEEK(NOW(),1) GROUP BY DATE(orderDateTime)")->fetchAll();
foreach($thisWeekQ as $thisweek){
$thisWeekA[] = array( $thisweek['Date'], $thisweek['totalCount'] );
}
array(2) {
[0]=>
array(4) {
["Date"]=>
string(1) "2"
[0]=>
string(1) "2"
["totalCount"]=>
string(1) "3"
[1]=>
string(1) "3"
}
[1]=>
array(4) {
["Date"]=>
string(1) "3"
[0]=>
string(1) "3"
["totalCount"]=>
string(1) "2"
[1]=>
string(1) "2"
}
}
for weekly data use for loop in your php update it as,
Logic only 7 days in a week of instead of using foreach from the result data we can use the for loop for seven days
i.e., similarly use for years also
$thisWeekA = array();
$thisWeekQ = $database->query("SELECT WEEKDAY(orderDateTime) Date, COUNT(clientID) totalCount FROM orders WHERE YEARWEEK(orderDateTime,1) = YEARWEEK(NOW(),1) GROUP BY DATE(orderDateTime)")->fetchAll();
for ($i = 0; $i <= 6; $i++) {
if ($thisWeekQ[$i]['Date'] == $i) {
$thisWeekA[$i][] = array($thisWeekQ[$i]['Date'], $thisWeekQ[$i]['totalCount']);
} else {
$thisWeekA[$i][] = array($i, 0);
}
}
You might want to think about building your arrays more like this:
var dow = [];
dow[0] = 1;
dow[1] = 4;
dow[6] = 12;
At this point you can populate your array for your chart
var chartData = [];
for (var i=0; i<7; i++){
chartData[i] = [i, (dow[i] === undefined ? 0 : dow[i])];
}
I managed to figure out a way of doing this. Thanks for pointing me in the direction of the For loop!
This is what I have came up with and works!
function arrayhunt($products, $field, $value){
foreach($products as $key => $product){
if ($product[$field] == $value){
return $key;
}
}
return false;
}
$i = 0;
for ($i = 0; $i <= 6; $i++) {
$keys = arrayhunt($thisWeekQ,"Date",$i);
if($keys !== FALSE){
$thisWeekA[] = array($thisWeekQ[$keys]['Date'], $thisWeekQ[$keys]['totalCount']);
} else {
$thisWeekA[] = array($i, 0);
}
$keys = "";
}
Hopefully someone finds this useful later.
Its my first time working with multidimensional arrays in php. I need to change the second number in each sub array.
What I want is to check if the Id in the array matches the Id from the database. When the two match I want to change the 2nd entry in the sub array by adding a number to it. If the Id from the query does not match anything in the list I want a new sub array to be pushed to the end of the array with the values of Id and points_description.
Also, if its helpful, my program right now does find the matches. The only thing is, it does not update the 2D array.
$array = array(array());
while ($row_description = mysqli_fetch_array($query_description)) {
$check = 1;
$is_match = 0;
foreach ($array as $i) {
foreach ($i as $value) {
if ($check == 1) {
if ($row_description['Id'] == $value) {
//$array[$i] += $points_description;
$is_match = 1;
}
}
$check++;
$check %= 2; //toggle between check and points
}
}
if ($is_match == 0) {
array_push($array, array($row_description['Id'], $points_description));
}
}
I feel like Im doing this so wrong. I just want to go through my 2D array and change every second value. The expected output should be a print out of all the Ids and their corresponding point value
I hope this is helpful enough.
Example: $row_description['Id'] = 2 and $array = array(array(2,1), array(5,1) , array(6,1))
output should be $array = array(array(2,4), array(5,1) , array(6,1))
if $row_description['Id'] = 3 and $array = array(array(2,1), array(5,1) , array(6,1))
output should be $array = array(array(2,4), array(5,1) , array(6,1),array(3,3))
By default PHP will copy an array when you use it in a foreach.
To prevent PHP from creating this copy you need to use to reference the value with &
Simple example :
<?php
$arrFoo = [1, 2, 3, 4, 5,];
$arrBar = [3, 6, 9,];
Default PHP behavior : Make a copy
foreach($arrFoo as $value_foo) {
foreach($arrBar as $value_bar) {
$value_foo *= $value_bar;
}
}
var_dump($arrFoo);
/* Output :
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
*/
ByReference : Don't create the copy :
foreach($arrFoo as &$value_foo) {
foreach($arrBar as $value_bar) {
$value_foo *= $value_bar;
}
}
var_dump($arrFoo);
/* Output :
array(5) {
[0]=>
int(162)
[1]=>
int(324)
[2]=>
int(486)
[3]=>
int(648)
[4]=>
&int(810)
}
*/
It seems this is a general question of programming logic, as this issue seems to arise in my code regardless of what language it's coded in.
Basically I have 2 nested for loops, inside a for loop. The purpose of these for loops is to enumerate all possible values between two sets of values.
The problem with the code is that is the second set of values contains a 0 the values won't enumerate.
Say for example we want to enumerate all values between 0,0,0 and 1,1,1, this works perfectly fine, as each nested loop is processed. However is we try to calculate between 0,0,0 and 0,1,0 the loop will not continue on to the next loop, instead it will exit the loop and continue on to the rest of the code.
for ($i1=$coords1[0]; $i1<=$coords2[0]; $i1++) { //if $coords2[0] = 0 loop will fail
for ($i2=$coords1[1]; $i2<=$coords2[1]; $i2++) { //if $coords2[1] = 0 loop will fail
for ($i3=$coords1[2]; $i3<=$coords2[2]; $i3++) {//if $coords2[2] = 0 loop will fail
$blocks.= $i1.",".$i2.",".$i3."|";
}
}
}
return $blocks;
Full code: PHPFIDDLE
Okay, to copy this over from our chat, I believe this is the solution:
<?php
$set1 = explode(",", '1,0,1');
$set2 = explode(",", '1,1,0');
$allbetween = _allbetween($set1, $set2);
echo 'All Between: '.$allbetween.'<br/>';
$allcount = count(explode("|", $allbetween))-1;
echo 'Number Of Blocks: '.$allcount;
function _allbetween($coords1, $coords2) {
$blocks = "";
for ($i=0; $i<=2; $i++) {
if ($coords1[$i] > $coords2[$i]) {
$tmp = $coords1[$i];
$coords1[$i] = $coords2[$i];
$coords2[$i] = $tmp;
}
}
for ($i1=$coords1[0]; $i1<=$coords2[0]; $i1++)
{
for ($i2=$coords1[1]; $i2<=$coords2[1]; $i2++)
{
for ($i3=$coords1[2]; $i3<=$coords2[2]; $i3++)
{
$blocks.= $i1.",".$i2.",".$i3."|";
}
}
}
return $blocks;
}
?>
DEMO HERE
The reason this works is that there is a swap loop at the beginning of your function, which swaps any of the three sets of values if the first is greater than the second. This ensures that all values "between" them can be calculated.
Edit: Fixing the demo link to the correct URL
the break; will do. see more information in the link:
http://www.php.net/manual/en/control-structures.break.php
Your loops will never loop as you are setting each initial value to the end range value. Instead use:
for ($i1=0; $i1<=$coords2[0]; $i1++)
...
etc
In terms of fall-through, try the following:
for ($i1=0; $i1<=$coords2[0] + 1; $i1++)
...
etc
Here's the problem: Dumping out your two $coords arrays:
$coords1:
array(3) {
[0]=>
string(1) "0"
[1]=>
string(1) "0"
[2]=>
string(1) "1"
}
$coords2:
array(3) {
[0]=>
string(1) "1"
[1]=>
string(1) "0"
[2]=>
string(1) "1"
}
On your first iteration:
$coords1[0] => 1
$coords2[0] => 0
1 <= 0 -> FALSE
so your outermost loop NEVER executes at all.
I think you are searching for
GOTO function
And for the
Continue function
I'm trying to get the previous and next value in an dynamic array so I can set those values on my links to the next and previous page. I get the dynamic array from my database and returns the ID's of the category I'm in right now.
As an example, I'm on page ID 6 with category Food than the array is filled with the ID's of other pages with the category Food.
My array works and returns the right values but when I try to get the previous and next ID from my current ID, it returns nothing.
Here is the code with how I fill my array and the var_dump of the array and how I try to get the previous and next value.
$results = array();
while($row = mysql_fetch_array($result)){
$results[$row[0]] = $row[0];
}
array(3) {
[1]=> string(1) "1"
[4]=> string(1) "4"
[6]=> string(1) "6"
}
$index = array_search($id, $results);
if($index !== FALSE){
$prev = $results[$index + 1];
$next = $results[$index - 1];
}
The variables $next and $prev return nothing but when I check $results[$index] it return the right ID from the current page. I really can't see anymore what is going wrong.
How about such code?
$results = array();
while($row = mysql_fetch_array($result)){
$results[] = $row[0];
}
$index = array_search($id, $results);
if ($index !== FALSE){
$prev = $results[$index + 1];
$next = $results[$index - 1];
}
The problem you have is:
4 - 1 != 1
and
4 + 1 != 6
That's why you get NULLs and notices (or you get notices and do not see them).
Hi I am trying to count the number of duplicate values in a associative array that looks like this:
array(3) { [0]=> array(3) { ["Title"]=> string(25) "hello"
["Price"]=> int(50)
["Count"]=> int(1) }
[1]=> array(3) { ["Title"]=> string(35) "world"
["Price"]=> int(50)
["Count"]=> int(1) }
[2]=> array(3) { ["Title"]=> string(25) "hello"
["Price"]=> int(50)
["Count"]=> int(1) } }
As you can see here there is a duplicate value in the "Title" lable I want to count them and add one to the "Count" part. I started to do something like this:
$prodArray = array();
// Add the values to the array if it's the first time it occurs.
if (!in_array($row['prodTitle'], $prodArray["Title"]))
{
array_push($prodArray,
array( Title => $row['prodTitle'],
Price => $row['prodPrice'],
Count => 1)
);
}
else
{
//Add one to the count for the current item.
}
the thing is I can't access the "Title" element in the array through the in_array function. Any suggestions are welcome.
If you want to detect dups in an array that you are creating, something like this avoid having to go through the array multiple times:
$arr=array();
while($row = mysql_fetch_array($result)) {
$arr[$row['prodTitle']] = isset($arr[$row['prodTitle']])
? $arr[$row['prodTitle']] +1
: 0;
}
$dups = array_keys(array_filter($arr)); //any key => 0 will be filtred out
If you want to just get the dups directly by SQL, have a look at this:
Your current query--
SELECT prodTitle
FROM product
WHERE prodTitle != '{$keyword}'
AND creditCard IN( SELECT creditCard FROM product WHERE prodTitle ='{$keyword}');
which given data like this
prod cc
A 1
A 2
A 3
A 1
A 1
B 15
B 1
B 2
B 21
C 10
C 1
returns this set (with $keyword=='A'):
prod
B
B
C
An aggregate query that returns only records where credit cards used on non-X were also used on X at least twice --
SELECT p1.prodTitle, COUNT(p2.creditCard) AS numrecords
FROM product p1
JOIN product p2
ON (p1.creditCard = p2.creditCard)
WHERE p1.prodTitle != '{$keyword}'
AND p2.prodTitle = '{$keyword}'
GROUP BY p1.prodTitle
HAVING COUNT(p2.creditCard) > 1;
given the same data, returns this set:
prod num
B 2
Doing an aggregate query avoids all the messing about with loops. Here's a link to the MySQL list of aggregate functions.
Okey so I found my solution and I made it look something like this probably not he most efficient way but it works:
$prodArray = array();
$ar = array();
$query ="THE QUERY";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result))
{
array_push($ar, $row['prodTitle']);
}
function findDuplicates($data,$dupval) {
$nb= 0;
foreach($data as $key => $val)
if ($val==$dupval) $nb++;
return $nb;
}
$uniarr = array_unique($ar);
//Will run the function findDuplicates for each unique title in the array
for ($i = 0; $i < sizeof($uniarr); $i++)
{
$count = findDuplicates($ar, $uniarr[$i]);
array_push($prodArray, array( Title => $uniarr[$i], Count => $count));
}
//Displays 2 of the results in the array
for ($c = 0; $c < 2; $c++)
{
echo "The title:".$prodArray[$c]["Title"]." And the amount:".$prodArray[$c]["Count"];
echo "<br />";
}
So that's pretty much it feel free to post your comments on this and if you have any improvements feel free to post them.