Query missing months in which we haven't sold anything? - php

My query is:
$sql="SELECT COUNT(`Variant`) AS tsold, MONTHNAME(`sold_date`) AS mname FROM `vehicle_sold` GROUP BY MONTH(`sold_date`) ";
$result = mysqli_query($conn,$sql);
while($row = mysqli_fetch_array($result)) {
echo $row["mname"],"---", $row["tsold"],"<br />";
}
which gives me the below result:
January---1
February---2
March---7
April---11
May---6
July---1
There are no sales in June so what I want is the query to return "June---0" for example. If it also shows the next months up to December it's ok. I'd like the following output:
January---1
February---2
March---7
April---11
May---6
June---0
July---1
Aug---0
Sept---0
Oct---0
Nov---0
Dec---0

Use an array of month names -
$months = array('January', 'February', ..., 'December');
Generate and array with the data returned from database -
while($row = mysqli_fetch_array($result)) {
$data[$row["mname"]] = $row["tsold"];
}
And print them accordingly -
foreach($months as $value) {
echo $value.' - '. (array_key_exists($value, $data) ? $data[$value] : 0) . '<br/>';
}

I assume you have actually no data in the database if you did not sell anything. Hence its a bit hard to generate a month without info.
You want an array with all the months, corresponding with the amount of sales.
I would suggest you make something like this:
Prepare an array with the months with all the values on 0 as default (you can make this array list 'nicer', but just now as example).
$data['March'] = 0;
$data['April'] = 0;
Now you can iterate like you did
while($row = mysqli_fetch_array($result)) {
$data[$row["mname"]] = $row["tsold"];
}
If it does not get filled by the database, the value would still be 0. Otherwise it gets overwritten by the database value.

Related

How to assign value to an array in while loop in php from mysqli result to make a counter to filter another while loop?

How to assign value to an array in while loop in php from mysqli result to make a counter to filter another while loop??
I want to assign something like this for my counter variable:
$counter = array("6:00 Am" => 0, "8:00 Am" => 0, "10:00 Am" => 0);
For this code:
//This is from transaction table
$stm2 = "SELECT tr_sched FROM transaction WHERE tr_date = CURRENT_DATE()";
$res2 = $conn->query($res2);
while($rows5 = $res2->fetch_assoc())
{
//Not working
$counter[] = array($rows5['tr_sched'] => 0)
}
So I can filter this another while loop if the schedule time is greater than to my limit variable, like this:
//This is from my schedule table
$stm = "SELECT sc_time FROM schedule GROUP BY sc_time";
$res = $conn->query($stm);
$counter = array();
while($row4 = $res4->fetch_assoc())
{
//Note working
if($counter[$row4['sc_time']] >= $limit/*=10*/)
{
echo "<option disabled="">" . $row4['sc_time'] . "</option>";
}
else
{
echo "<option>" . $row4['sc_time'] . "</option>";
}
}
The goal of all the codes above is to display all schedule time from schedule table as an option for select element and if the schedule time is already have a 10 records or greater than(limit variable) on my transaction table for today it will display as option but disable so it can't be selected by user.
I hope you get what I mean, I will try to keep active to answer if you have something to clarify about my question.
You don't need the while loop at all.
You can use array functions to populate the array with static values.
$stm2 = "SELECT tr_sched FROM transaction WHERE tr_date = CURRENT_DATE()";
$res2 = $conn->query($stm2);
// get values from a single column
$keys = array_column($res2->fetch_all(MYSQLI_ASSOC), 'tr_sched');
// create an array with all values as 0 and keys from $keys
$counter = array_fill_keys($keys, 0);
Of course, don't reset the array later on with $counter = array();
If you want to loop anyway, then you can use a simple foreach loop.
$stm2 = "SELECT tr_sched FROM transaction WHERE tr_date = CURRENT_DATE()";
$res2 = $conn->query($stm2);
foreach($res2 as $rows5) {
$counter[$rows5['tr_sched']] = 0;
}

How to save query in multidimesional array?

I have this script executing as a cron job everyday to update days remaining to pay invoices. I first query every row of my table and attempt to store the data in a multidimensional array but this seems to be storing everything I query in the first element of my array.
Here's my script:
<?php
include '../inc/dbinfo.inc';
ini_set("log_errors", 1);
ini_set("error_log", "/tmp/php-error.log");
error_log( "################################################# UpdateVendorInvoiceDays.php #################################################" );
$three = 3;
$fetchAllInvoices = "SELECT VENDORINVOICEID, VdrInvoiceReceived, PaymentDue, COUNT(*), DATEDIFF(PaymentDue, NOW()) FROM tblVendorInvoices WHERE VdrInvoiceStatusID != ?";
$getInvoices = $conn->prepare($fetchAllInvoices);
$getInvoices->bind_param("i", $three);
$getInvoices->execute();
$result = $getInvoices->get_result();
$rows = array();
$j = 0;
while($row = $result->fetch_assoc())
{
$rows[$j][] = $row;
$j++;
}
echo json_encode($rows[0][0]); //Only outputs one row
//UPDATE DAYS REMAINING IN EACH ENTRY THAT ISNT PAID
$updateDaysRemaining = "UPDATE tblVendorInvoices SET DaysRemaining = ? WHERE VENDORINVOICEID = ? AND VdrInvoiceStatusID ! = ?";
$setDays = $conn->prepare($updateDaysRemaining);
$k = 0; //incrementor
$numberOfEntries = $rows['COUNT(*)'];
for($k;$k<$numberOfEntries;$k++){
$setDays->bind_param("iii", $rows[$k]["DATEDIFF(PaymentDue, NOW())"],
$rows[$k]['VENDORINVOICEID'], $three);
if($setDays->execute()){
error_log('Cron success');
}else{
error_log('Cron fail');
}
}
?>
Currently the output from my first query is:
[[{"VENDORINVOICEID":88,"VdrInvoiceReceived":"2018-08-21","PaymentDue":"2018-07-27","COUNT(*)":2,"DATEDIFF(PaymentDue, NOW())":-25}]]
and my error log only gives me a notice for $rows['COUNT(*)'] being undefined (which makes sense)
I've looked at other answers here but they don't seem to have the same structure as I do.
EDIT: I also have 2 rows in my database but this only puts out one. I forgot to mention this.
There are a couple of simplifications to get all of the rows. Instead of...
while($row = $result->fetch_assoc())
{
$rows[$j][] = $row;
$j++;
}
echo json_encode($rows[0][0]);
You can just return all rows using fetch_all()...
$rows = $result->fetch_all (MYSQLI_ASSOC);
echo json_encode($rows);
Then encode the whole array and not just the one element - which is what $rows[0][0] was showing you.
As for you other problem - change in your select statement to
COUNT(*) as rowCount
and then you can use this alias for the field reference...
$rows['COUNT(*)']
becomes
$rows['rowCount']

Multi Dimensional array printing

I'm trying very hard to display this multi dimentional array for past 3 to 4 days to no avail.
All I need to do is to display like below:
carName:
carImage:
days:
amount: // this is where I'm facing the problem to display all the days and amount related to specific car..One car will have few days and amount quoted for each day.
//pls look at my code and help... Thanks
<?php
mysql_select_db($database);
$query_showall = "SELECT rental.*,
car_name.*,
gallery.*,
car_make.*
FROM rental,
car_name,
gallery,
car_make
WHERE car_name.carName_id = gallery.carName_id
AND car_name.carMake_id = car_make.carMake_id
AND rental.carName_id = car_name.carName_id
GROUP BY rental.carName_id";
$result_showall = mysql_query($query_showall) or die(mysql_error());
while($row_showall = mysql_fetch_array($result_showall)) {
$carMake_all = $row_showall['carName'];
$carmake_1[$row_showall['carName_id']][] = $row_showall;
}
foreach($carmake_1 as $make_1=>$name_1) {
foreach($name_1 as $n_1) {
echo $n_1['carName'].'<br/>';
echo $n_1['gallery'].'<br/>';
/* I need to loop through the rental table
to retrieve num of days and amount for
each car here.. */
echo $n_1['rental_days'].'<br/>';
echo $n_1['rental_amount'].'<br/>';
}
}
?>
edit without GROUP BY But how can I stop the carName and imageName not to repeat ?
<?php
mysql_select_db($database);
$query_showall="SELECT rental.*,car_name.*,gallery.*,car_make.* FROM rental,car_name,gallery,car_make WHERE car_name.carName_id=gallery.carName_id AND
car_name.carMake_id=car_make.carMake_id AND rental.carName_id=car_name.carName_id ORDER BY rental_days ASC";
$result_showall=mysql_query($query_showall)or die(mysql_error());
while($row_showall=mysql_fetch_array($result_showall))
{
$carMake_all=$row_showall['carName'];
$carmake_1[$row_showall['carName_id']][]=$row_showall;
}
foreach($carmake_1 as $make_1=>$name_1)
{
foreach($name_1 as $n_1)
{
echo $n_1['carName'].'<br/>';
echo $n_1['gallery'].'<br/>';
echo $n_1['rental_days'].'<br/>';
echo $n_1['rental_amount'].'<br/>';
}
}
?>
Okay, I'll take a shot at this. What I would do is rebuild the array before you try to dump it out so that all your data is organized the way you want it to display, that way at each step of the foreach you can only display what you want.
This code would use your SQL statement without the group by, which as you stated is including all the data.
// Start with an empty array...
$cars = array();
// Loop over all your results
while($row_showall = mysql_fetch_array($result_showall)) {
// Set name, if the ID comes up again, it will be reset but won't hurt anything
$cars[$row_showall['carName_id']]['name'] = $row_showall['carName'];
// Set gallery, if the ID comes up again, it will be reset but won't hurt anything
$cars[$row_showall['carName_id']]['gallery'] = $row_showall['gallery'];
// Now, we add a new property called 'details' and put a new array in...
$cars[$row_showall['carName_id']]['details'][] = array(
// Storing a unique day
'days' => ['rental_days'],
// And a unique amount
'amount' => ['rental_amount']
);
}
// Loop over each entry in our array...
foreach($cars as $car) {
// Print out the name, once
echo $car['name'] . '<br />';
// Print out the gallery, once
echo $car['gallery'] . '<br />';
// Loop over all the details...
foreach($car['details'] as $detail) {
// Print out each day
echo $detail['days'] . '<br />';
// Print out each amount
echo $detail['amount'] . '<br />';
}
}

SQL Query not completing correctly - not sure why

Alright,
I've got a multiple select dropdown on a page called week-select, its selections get passed via ajax to my php page.
I can get the data just fine, but when the query runs it doesn't complete appropriately.
I've got this:
//Deal with Week Array
$weekFilter = $_GET['week']; /*This is fine, if it's 1 week the query works great (weeks are numbered 12-15), but if it is 2 weeks the result is formatted like this 12-13 or 13-14-15 or whichever weeks are selected*/
$weekFilter = str_replace("-",",",$weekFilter); /*This works to make it a comma separated list*/
.../*I deal with other variables here, they work fine*/
if ($weekFilter) {
$sql[] = " WK IN ( ? ) ";
$sqlarr[] = $weekFilter;
}
$query = "SELECT * FROM $tableName";
if (!empty($sql)) {
$query .= ' WHERE ' . implode(' AND ', $sql);
}
$stmt = $DBH->prepare($query);
$stmt->execute($sqlarr);
$finalarray = array();
$count = $stmt->rowCount();
$finalarray['count'] = $count;
if ($count > 0) { //Check to make sure there are results
while ($result = $stmt->fetchAll()) { //If there are results - go through each one and add it to the json
$finalarray['rowdata'] = $result;
} //end While
}else if ($count == 0) { //if there are no results - set the json object to null
$emptyResult = array();
$emptyResult = "null";
$finalarray['rowdata'] = $emptyResult;
} //end if no results
If I just select one week it works great and displays the appropriate data.
If I select multiple options (say weeks 12, 14 and 15) it runs the query but only displays week 12.
When I manually input the query in SQL, how I imagine this query is getting entered - it runs and displays the appropriate data. So if I put SELECT * FROM mytablename WHERE WK IN ( 12, 14, 15 ) it gets exactly what I want.
I can't figure out why my query isn't executing properly here.
Any ideas?
**EDIT: I make the array from the multiple selections a string using javascript on the front end before it is passed to the backend.
Your resulting query with values probably looks like this with a single value in IN:
… WK IN ("12,14,15") …
Either use one placeholder for each atomic value:
if ($weekFilter) {
$values = explode(",", $weekFilter);
$sql[] = " WK IN ( " . implode(",", array_fill(0, count($values), "?")) . " ) ";
$sqlarr = array_merge($sqlarr, $values);
}
Or use FIND_IN_SET instead of IN:
$sql[] = " FIND_IN_SET(WK, ?) ";
I don't think you can bind an array to a singular ? placeholder. Usually you have to put in as many ? values as there are elements in your array.
If your HTML is correct and your week select has name="week[]", then you will get an array back with $_GET['week'];, otherwise without the [] it will only give you 1 value. Then, you're doing a string replace, but it's not a string. Instead, try this:
$weekFilter = implode(',', $_GET['week']);

How can I copy a database table to an array while accounting for skipped IDs?

I previously designed the website I'm working on so that I'd just query the database for the information I needed per-page, but after implementing a feature that required every cell from every table on every page (oh boy), I realized for optimization purposes I should combine it into a single large database query and throw each table into an array, thus cutting down on SQL calls.
The problem comes in where I want this array to include skipped IDs (primary key) in the database. I'll try and avoid having missing rows/IDs of course, but I won't be managing this data and I want the system to be smart enough to account for any problems like this.
My method starts off simple enough:
//Run query
$localityResult = mysql_query("SELECT id,name FROM localities");
$localityMax = mysql_fetch_array(mysql_query("SELECT max(id) FROM localities"));
$localityMax = $localityMax[0];
//Assign table to array
for ($i=1;$i<$localityMax+1;$i++)
{
$row = mysql_fetch_assoc($localityResult);
$localityData["id"][$i] = $row["id"];
$localityData["name"][$i] = $row["name"];
}
//Output
for ($i=1;$i<$localityMax+1;$i++)
{
echo $i.". ";
echo $localityData["id"][$i]." - ";
echo $localityData["name"][$i];
echo "<br />\n";
}
Two notes:
Yes, I should probably move that $localityMax check to a PHP loop.
I'm intentionally skipping the first array key.
The problem here is that any missed key in the database isn't accounted for, so it ends up outputting like this (sample table):
1 - Tok
2 - Juneau
3 - Anchorage
4 - Nashville
7 - Chattanooga
8 - Memphis
-
-
I want to write "Error" or NULL or something when the row isn't found, then continue on without interrupting things. I've found I can check if $i is less than $row[$i] to see if the row was skipped, but I'm not sure how to correct it at that point.
I can provide more information or a sample database dump if needed. I've just been stuck on this problem for hours and hours, nothing I've tried is working. I would really appreciate your assistance, and general feedback if I'm making any terrible mistakes. Thank you!
Edit: I've solved it! First, iterate through the array to set a NULL value or "Error" message. Then, in the assignations, set $i to $row["id"] right after the mysql_fetch_assoc() call. The full code looks like this:
//Run query
$localityResult = mysql_query("SELECT id,name FROM localities");
$localityMax = mysql_fetch_array(mysql_query("SELECT max(id) FROM localities"));
$localityMax = $localityMax[0];
//Reset
for ($i=1;$i<$localityMax+1;$i++)
{
$localityData["id"][$i] = NULL;
$localityData["name"][$i] = "Error";
}
//Assign table to array
for ($i=1;$i<$localityMax+1;$i++)
{
$row = mysql_fetch_assoc($localityResult);
$i = $row["id"];
$localityData["id"][$i] = $row["id"];
$localityData["name"][$i] = $row["name"];
}
//Output
for ($i=1;$i<$localityMax+1;$i++)
{
echo $i.". ";
echo $localityData["id"][$i]." - ";
echo $localityData["name"][$i];
echo "<br />\n";
}
Thanks for the help all!
Primary keys must be unique in MySQL, so you would get a maximum of one possible blank ID since MySQL would not allow duplicate data to be inserted.
If you were working with a column that is not a primary or unique key, your query would need to be the only thing that would change:
SELECT id, name FROM localities WHERE id != "";
or
SELECT id, name FROM localities WHERE NOT ISNULL(id);
EDIT: Created a new answer based on clarification from OP.
If you have a numeric sequence that you want to keep unbroken, and there may be missing rows from the database table, you can use the following (simple) code to give you what you need. Using the same method, your $i = ... could actually be set to the first ID in the sequence from the DB if you don't want to start at ID: 1.
$result = mysql_query('SELECT id, name FROM localities ORDER BY id');
$data = array();
while ($row = mysql_fetch_assoc($result)) {
$data[(int) $row['id']] = array(
'id' => $row['id'],
'name' => $row['name'],
);
}
// This saves a query to the database and a second for loop.
end($data); // move the internal pointer to the end of the array
$max = key($data); // fetch the key of the item the internal pointer is set to
for ($i = 1; $i < $max + 1; $i++) {
if (!isset($data[$i])) {
$data[$i] = array(
'id' => NULL,
'name' => 'Erorr: Missing',
);
}
echo "$i. {$data[$id]['id']} - {$data[$id]['name']}<br />\n";
}
After you've gotten your $localityResult, you could put all of the id's in an array, then before you echo $localityDataStuff, check to see
if(in_array($i, $your_locality_id_array)) {
// do your echoing
} else {
// echo your not found message
}
To make $your_locality_id_array:
$locality_id_array = array();
foreach($localityResult as $locality) {
$locality_id_array[] = $locality['id'];
}

Categories