Name of object in array causes a change in order - php

With the following code:
//turn items into an array
$item_array = array('abc','xyz2','Good','nice-b');
//implode items, turn into string
$item_implode = join("','", $item_array);
//declare an overall array for result
$product_items = array();
$productList = array();
$result = $mysqli->query("SELECT Name, WebsitePrice as price, WebsiteStock as stock from table_products where Name IN ('$item_implode')");
if ($result->num_rows > 0) {
$x = 1;
// output data of each row
while($row = $result->fetch_assoc()) {
$product_items[$x]["Name"] = $row['Name'];
$product_items[$x]["price"] = $row['price'];
$product_items[$x]["stock"] = $row['stock'];
$x = $x + 1;
}
} else {
echo "0 results";
}
I'm getting this output:
abc- 99 - yes
xyz - 20 - yes
Good - 30 - yes
nice-b - 55 - yes
But when I use an item called Hello1 instead of Good, like this:
$item_array = array('abc','xyz2','Hello1','nice-b');
I'm getting this output:
abc- 99 - yes
Hello1 - 77 - yes
xyz - 20 - yes
nice-b - 55 - yes
Meaning that the name of the object is causing some change in the order of the array, and it becomes the second item, even though it should be the third one.
What's causing this?

Use ORDER BY FIELD(Name, 'abc','xyz2','Good','nice-b'); in your query. You could use $item_implode for reusability.
[Fetched from comments]

In the SQL world, order is not an inherent property of a set of data. Thus, you get no guarantees from your RDBMS that your data will come back in a certain order -- or even in a consistent order -- unless you query your data with an ORDER BY clause.
There is no guarantee that MySQL will return the results in the order you set the IDs in the IN clause.
Later edit: Based on your last comment you can do something like this:
if ($result->num_rows > 0) {
$product_items = array_flip($item_array);
// output data of each row
while($row = $result->fetch_assoc()) {
$product_items[$row['Name']] = array();
$product_items[$row['Name']]["Name"] = $row['Name'];
$product_items[$row['Name']]["price"] = $row['price'];
$product_items[$row['Name']]["stock"] = $row['stock'];
}
}

Related

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']

Mysql Data Only Pulling Last Result Into Json Array

I'm pulling multiple rows from a table and formatting them to this standard: 3 Swords, 5 Daggers, etc.
Well When I try to put that data into a json Array, It's only pulling the last result as this [{"weapons":"You Used: 3 Rusty Dagger's, "}] Which it should say: [{"weapons":"You Used: 3 Rusty Dagger's, 2 Swords"}]
Here's The Query I'm currently using, Which will show perfectly inside of the while loop:
$get_weapons = mysql_query("SELECT
O.player_id,
O.item_id,
O.name,
O.attack,
O.defense,
O.type,
O.owned,
(SELECT
sum(owned) FROM items_owned
WHERE owned <= O.owned AND player_id=$id) 'RunningTotal'
FROM items_owned O
HAVING RunningTotal <= $mob_avail
ORDER BY attack DESC");
// Get Weapon Info
while($weapon = mysql_fetch_array($get_weapons)){
$weapon_id = $weapon['item_id'];
$weapon_name = $weapon['name'];
$weapon_attack = $weapon['attack'];
$weapon_defense = $weapon['defense'];
$weapon_owned = $weapon['owned'];
// Formatting Weapons Message
$weapon_message = 'You Used: '.$weapon_owned.' '.$weapon_name.'\'s, ';
}
$data[] = array('weapons'=>$weapon_message);
echo json_encode($data);
I understand that the $data array is outside of the while loop, But I'm only needing a total of one arrays, so I'm kind of stuck on what to do to fix this issue. Any help would be awesome
You should add one static variable before append the results into the message.
Here is the reference answer:
$get_weapons = mysql_query("SELECT O.player_id, O.item_id, O.name, O.attack, O.defense, O.type, O.owned, (
SELECT sum(owned) FROM items_owned WHERE owned <= O.owned AND player_id=$id) 'RunningTotal' FROM items_owned O HAVING RunningTotal <= $mob_avail ORDER BY attack DESC");
// Initialize the message
$weapon_message = 'You Used: ';
// Get Weapon Info
while($weapon = mysql_fetch_array($get_weapons)){
$weapon_id = $weapon['item_id'];
$weapon_name = $weapon['name'];
$weapon_attack = $weapon['attack'];
$weapon_defense = $weapon['defense'];
$weapon_owned = $weapon['owned'];
// Formatting Weapons Message
$weapon_message = $weapon_message.$weapon_owned.' '.$weapon_name.'\'s, ';
}
$data[] = array('weapons'=>$weapon_message);
echo json_encode($data);

Display date once and display results under the respective date. [MySQL/PHP]

$query_ListAbsence = "SELECT count(dated) as dtd, classed, name FROM att group by dtd, classed by dtd desc";
$la = mysql_query($query_la, $sshost) or die(mysql_error());
$row_la = mysql_fetch_assoc($la);
do{
....
}while ($row_la = mysql_fetch_assoc($la));
I want to result to show as
--date--
name1 - classed1
name2 - classed2
--another date---
namea - classeda
nameb - classedb
and so on...
But when inside the do{}while loop the date is displayed the number of times the loop runs. Can i display the results as shown with a single table. This is done by MySQL / PHP.
$arr = array();
while($row = mysql_fetch_assoc($la)) {
$arr[$row['your_date']][] = $row;
}
And than loop through $arr array;

Trying to sort and display data from a single mysql query

I've looked for about an hour. I may even be looking for the wrong thing, because I'm sure this is a common practice. In the past, I would have just ran mutliple querys or had something hard coded, but I'm trying to do things the most efficient way.
I have a query that brings back this data:
factoryId | serviceID | serviceName
1 1001 repair
1 1002 recycle
1 1003 transfer
2 1001 repair
2 1002 recycle
2 1003 transfer
3 1001 repair
3 1002 recycle
3 1003 transfer
I need to put it into sections with headers...
// switch statement determines factory name from id ?>
Factory One
Repair
Recycle
Transfer
Factory Two
Repair
Recycle
Transfer
Factory Three
Repair
Recycle
Transfer
I think the solution is with multi-dimensional arrays, but not sure how to write the array, and then (2 foreach loops?) to echo the formatted result.
Here this is what you can do, I am not using the query but generated an array which is similar to mysql_fetch_assoc();
<?php
$array[] = array("factory"=>"Factory One","serviceName"=>"repair");
$array[] = array("factory"=>"Factory One","serviceName"=>"recycle");
$array[] = array("factory"=>"Factory One","serviceName"=>"transfer");
$array[] = array("factory"=>"Factory Two","serviceName"=>"repair");
$array[] = array("factory"=>"Factory Two","serviceName"=>"recycle");
$array[] = array("factory"=>"Factory Two","serviceName"=>"transfer");
$array[] = array("factory"=>"Factory three","serviceName"=>"repair");
$array[] = array("factory"=>"Factory three","serviceName"=>"recycle");
$array[] = array("factory"=>"Factory three","serviceName"=>"transfer");
$group_array = array();
foreach($array as $key=>$val){
$group_array[$val["factory"]][] = $val["serviceName"];
}
foreach($group_array as $key=>$val){
echo '<b>'.$key.'</b><br />';
foreach($val as $k=>$v){
echo '-'.$v.'<br />';
}
}
?>
The first loop is similar to looping the query result and creating a group array and then finally loop the group array to display the data.
Try the below code. Make sure to write your query appending ASC or DESC to factoryID
<?php
//Place a counter for factoryId
$countid_fid = 1;
$reset = 0; //this decides if the title should be printed or not. 1 means dont print.
//loop
while($row = mysql_fetch_object($q)) {
$fid = $row->factoryID;
if($countid_fid == $fid) {
if($reset = 0) {
echo $row->serviceName; //title
$reset = 1;
}
}else{
$reset = 0;
}
//rest of your code to show data
}
?>
Hope this help
SELECT * FROM factory GROUP BY factoryId;

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