bug nested foreach loops - php

I have a problem with my code, it two nested foreach loops:
$message = mysqli_query($mysqli, "SELECT * FROM messages where pseudo ='".$Pseudo."'");
while ($data = mysqli_fetch_assoc($message)) {
$items[] = $data;
}
$items = array_reverse($items ,true);
foreach($items as $item) {
echo"".$item['msg']."";
$commentaires = mysqli_query($mysqli, "SELECT * FROM commentaires where msg ='".$item['msg']."' and profil ='".$item['pseudo']."'");
while($row = $commentaires->fetch_array()) {
$rows[] = $row;
}
foreach($rows as $row) {
$abc = $row[0];$commen = $row[3];
echo "$abc : $commen";
}
}
so i've 2 entries in "messages" and 4 entries for "commentaires" 2 for the first entry of "messages" and 2 for the second. I want that :
message1
-commentaire 1
-commentaire 2
message2
-commentaire 3
-commentaire 4
and this is what i have :
message1
-commentaire 1
-commentaire 2
message2
-commentaire 1
-commentaire 2
-commentaire 3
-commentaire 4
i've search during 2 hours i don't have found a solution in mysqli :(
(when i do
mysqli_data_seek($commentaires ,0);
that don't change anything)
sorry for my bad English :c

Im pretty sure that this:
while($row = $commentaires->fetch_array()){$rows[] = $row;}
appends rows to existing array..
which means you have to clear $rows before appending new data to it, if you want it to work as written.
I'm no PHP shark, but I do believe
unset($rows);
would do the trick

Related

Name of object in array causes a change in order

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

Format JSON with PHP

I need some helping formatting my JSON correctly. Create parent objects for each of the activities and then add children to them. With the example data below it would be one parent activity for 'Test' with two children and another parent for 'Test2' with three children. I've linked in two jsonblobs with the format i'm getting and the format I need. Any help would be appreciated.
+---------------+-------+--------------+------------+------------+--------+
| ACTIVITY_NAME | GROUP | START_DATE | END_DATE | COMPLETED | TOTAL |
+---------------+-------+--------------+------------+------------+--------+
| Test | 1 | 04/30/2015 | 05/01/2015| 10 | 15 |
| Test | 2 | 04/30/2015 | 05/01/2015| 20 | 25 |
| Test2 | 1 | 05/2/2015 | 05/03/2015| 30 | 35 |
| Test2 | 2 | 05/2/2015 | 05/03/2015| 40 | 45 |
| Test2 | 3 | 05/2/2015 | 05/03/2015| 50 | 55 |
+---------------+-------+--------------+------------+------------+--------+
PHP:
<?php
include("connect.php");
if( $conn === false ) {
echo "Could not connect.\n";
die( print_r( sqlsrv_errors(), true));
}
/* Set up and execute the query. */
$sql = "<query>";
$stmt = sqlsrv_query( $conn, $sql);
do {
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$json[] = $row;
}
} while ( sqlsrv_next_result($stmt) );
foreach ($json as $result) {
$data[data][][$result['ACTIVITY_NAME']]['children'] = $result;
}
echo json_encode($data);
?>
This is what i'm getting: https://jsonblob.com/5550c921e4b002ae4e370469
This is what I need: https://jsonblob.com/5550c942e4b002ae4e370471
Edit -
Here is what my working script ended up looking like:
<?php
include("connect.php");
if( $conn === false ) {
echo "Could not connect.\n";
die( print_r( sqlsrv_errors(), true));
}
/* Set up and execute the query. */
$sql = "<query> ";
$stmt = sqlsrv_query($conn, $sql);
// This is where the data will be organized.
// It's better to always initialize the array variables before putting data in them
$data = array();
// Get the rows one by one
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
// Extract the activity name; we want to group the rows by it
$name = $row['ACTIVITY_NAME'];
$group = '';
$sdate = '';
$edate = '';
$completed = '';
$total = '';
$perc = '';
// Check if this activity was encountered before
if (! isset($data[$name])) {
// No, this is the first time; we will make room for it, first
$data[$name] = array(
// Remember the name
'ACTIVITY_NAME' => $name,
'MAINTENANCE_GROUP' => $group,
'START_DATE' => $sdate,
'END_DATE' => $edate,
'COMPLETED' => $completed,
'TOTAL_CLUSTERS' => $total,
'COMPLETE_PERC' => $perc,
// No children yet
'children' => array(),
);
}
// Put the row into the list of children for this activity
$data[$name]['children'][] = $row;
}
// Here, the entries in $data are indexed by the values they also have in 'ACTIVITY_NAME'
// If you want them numerically indexed, all you have to do is:
$data = array_values($data);
echo json_encode(array('data' => $data));
//echo json_encode($data);
?>
You didn't show the query/queries you run but for such a simple task I think a single query is enough. The outer do/while loop on sqlsrv_next_result() is not needed. You have to use it when you send more than one query (separated by semicolons) in a single call to sqlsrv_query().
You do not need to run two times through the result set. You can organize your data as soon as you get it from the database.
All you need is to check the values you get from the database and create the data structure as you need:
// ...
$stmt = sqlsrv_query($conn, $sql);
// This is where the data will be organized.
// It's better to always initialize the array variables before putting data in them
$data = array();
// Get the rows one by one
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
// Extract the activity name; we want to group the rows by it
$name = $row['ACTIVITY_NAME'];
// Check if this activity was encountered before
if (! isset($data[$name])) {
// No, this is the first time; we will make room for it, first
$data[$name] = array(
// Remember the name
'ACTIVITY_NAME' => $name,
// No children yet
'children' => array(),
);
}
// Put the row into the list of children for this activity
$data[$name]['children'][] = $row;
}
// Here, the entries in $data are indexed by the values they also have in 'ACTIVITY_NAME'
// If you want them numerically indexed, all you have to do is:
$data = array_values($data);
// That's all
Change these 3 lines:
foreach ($json as $result) {
$data[data][][$result['ACTIVITY_NAME']]['children'] = $result;
}
To this:
foreach ($json as $result) {
$data['data'][] = array('ACTIVITY_NAME' => $result['ACTIVITY_NAME'], 'children' => $result);
}
You can save the children fields in an array
do {
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$children = array("MAINTENANCE_GROUP" => $row["MAINTENANCE_GROUP"], "START_DATE" => $row["START_DATE"],
"END_DATE" => $row["END_DATE"], "COMPLETED" => $row["COMPLETED"], "TOTAL" => $row["TOTAL"] );
$json[] = array("MAINTENANCE_GROUP" => $row["MAINTENANCE_GROUP"], "children" => $children);
}
} while ( sqlsrv_next_result($stmt) );
i guess use below code
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
// Extract the activity name; we want to group the rows by it
$name = $row['ACTIVITY_NAME'];
// Check if this activity was encountered before
if (! isset($data[$name])) {
// No, this is the first time; we will make room for it, first
$data[$name] = array(
// Remember the name
'ACTIVITY_NAME' => $name,
// No children yet
'children' => array(),
);
}
// Put the row into the list of children for this activity
$data[$name]['children'][] = $row;
}
$json=json_encode($data);

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 to do SQL's GROUP BY using PHP?

I'd like to SELECT rows from a database table and group them using PHP instead of SQL based on a parameter (in this case by item).
SQL:
Clothes table
id item owner
1 shoes joe
2 pants joe
3 hat joe
4 pants joe
5 hat tom
SELECT * from Clothes where owner='joe'
1 shoes joe
2 pants joe
3 hat joe
4 pants joe
Here's how I'd like the results to look after using PHP instead of SQL's GROUP BY item
PHP :
1 shoes joe
2 pants joe //count 2
3 hat joe
I'm sure there is a PHP array function for this I'm just not familiar, thoughts?
The easiest way is to exploit the uniqueness of array keys:
$grouped = array();
while ($row = $db->fetchResult()) { // or however you get your data
if (isset($grouped[$row['item']])) {
$grouped[$row['item']]['count']++;
} else {
$grouped[$row['item']] = $row + array('count' => 1);
}
}
Using pseucode for the database access functions, I believe this should work:
$sql = "SELECT * from Clothes where owner='joe'";
$res = query($sql);
$arr = array();
while ($row = $res->fetch())
{
$arr[] = $row['item'];
}
$arr = array_unique($arr);
You should note that this might give you a "sparse array" (in other words, there may be gaps in the keys). And as said in the comments, it's usually better to do this in SQL if you have that option. Even if that means executing two similar queries.
function group($items, $field) {
$return = array();
foreach ($items as $item) {
$key = $item[$field];
if (isset($return[$key])) {
$return[$key]['count']++;
} else {
$return[$key] = $item;
$return[$key]['count'] = 1;
}
}
return $return;
}
print_r(group($results, "item"));

Recursive tree traversal with mysql through PHP

I am creating a questionnaire for a client that requires the questions to be organized by 3 layers of levels. I've successfully created the U.I. however I've been trying for the last 3 hours to pull data from a database in such a way that everything loads in the right place. The database is organized like so by the client so I have no control over it:
id description parentId
1 Level 1 0
2 Level 2 0
3 Level 1a 1
4 Level 1b 1
5 Level 1a1 3
I have found a similar question to mine on the site but when I attempted it's solution I got the following on repeat infinetly:
Code:
function makeList($par_id = 0) {
//your sql code here
$result = mysql_query("SELECT * FROM pB_test WHERE parentId = $par_id");
$pages = mysql_fetch_array( $result );
if (count($pages)) {
echo '<ul>';
foreach ($pages as $page) {
echo '<li>', $page['description'];
makeList($page['parentId']);
echo '</li>';
}
echo '</ul>';
}
}
makeList();
Output:
1
3
5
5
l
l
3
5
5
l
l
3
5
5
l
l
3
5
5
l
l
Does anyone know how to fix this and what the issue is exactly? Cheers
it's not good to call mysql server and fetch result each time
what if you have over 100 rows? or 200+
use this to query only once:
$result = mysql_query("SELECT * FROM test");
$arrs = array();
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$arrs[] = $row;
}
function build_tree($arrs, $parent_id=0, $level=0) {
foreach ($arrs as $arr) {
if ($arr['parent_id'] == $parent_id) {
echo str_repeat("-", $level)." ".$arr['name']."<br />";
build_tree($arrs, $arr['id'], $level+1);
}
}
}
build_tree($arrs);
common example for table
id name parent_id
Do this recursivly:
function printChildQuestions($parentid) {
$sql="SELECT * FROM pB_test WHERE parentID=$parentid";
$result=mysql_query($sql);
$i=0;
while (true) {
$row=mysql_fetch_array($result);
if (!$row) break;
if ($i==0) echo "<ul>";
$i=1;
echo '<li>'.$row['id'].' '.$row['description'].' '.$row['parentId'].'</li>';
printChildQuestions($row['id']);
}
if ($i>0) echo '</ul>';
}
printChildQuestions(0);

Categories