Grouping in a list - php - php

I have mysql result as you can see below. I want to make shop based list, how can I do in PHP?
SELECT shsv.shop_id, sv.shop, shsv.shop_product_id, shsv.shop_product, sum(shsv.cash)
FROM turerp_db.shop_has_sale_view shsv
left JOIN shop_view sv ON ( sv.shop_id = shsv.shop_id )
group by shsv.shop_id, shsv.shop_product_id
ID SHOP P_ID PRODUCT PRICE
10 SHOP_1 14 PRODUCT_1 322
11 SHOP_2 3 PRODUCT_2 2000
11 SHOP_2 5 PRODUCT_3 55
SHOP_1
PRODUCT_1
SHOP_2
PRODUCT_2
PRODUCT_3

You can use the power of associative nature of PHP arrays: http://www.php.net/manual/en/language.types.array.php
$shops = [];
$shops['SHOP_1'][] = 'PRODUCT_1';
$shops['SHOP_2'][] = 'PRODUCT_2';
$shops['SHOP_2'][] = 'PRODUCT_3';
var_dump($shops) will print:
array(2) {
["SHOP_1"]=>
array(1) {
[0]=>
string(9) "PRODUCT_1"
}
["SHOP_2"]=>
array(2) {
[0]=>
string(9) "PRODUCT_2"
[1]=>
string(9) "PRODUCT_3"
}
}
You should also refer to your mysql driver documentation. It is likely that some of its methods will return your data in a similar manner.

try this
$sql = mysql_query("SELECT * FROM tablename ORDER BY SHOP P_ID ASC");//your query
$cat = ""; //initialize $cat variable
while($row = mysql_fetch_assoc($sql)){
if($row['SHOP P_ID '] != $cat) echo "<h3>".$row['SHOP P_ID ']."</h3>\r\n";
echo "<p>".$row['PRODUCT']."</p>\r\n";
$cat = $row['SHOP P_ID'];
}

I have found solution myself, if you have better solution, please share us.
$query = $this -> db -> query('SELECT shsv.shop_id, sv.shop, shsv.shop_product_id, shsv.shop_product, sum(shsv.cash) AS cash_total FROM turerp_db.shop_has_sale_view shsv left JOIN shop_view sv ON ( sv.shop_id = shsv.shop_id ) group by shsv.shop_id, shsv.shop_product_id');
$shops= $query -> result();
$count = 0;
echo '<table>';
foreach ($shops as $shop) {
if($count == 0){
echo '<thead><tr><th colspan="2">'.$shop->shop.'</th></tr></thead>';
echo '<tbody>';
echo '<tr><td>'.$shop->shop_product.'</td><td>'.$shop->cash_total.'</td></tr>';
$shop_id = $shop -> shop_id;
}
else {
if($shop_id == $shop -> shop_id){
echo '<tr><td>'.$shop->shop_product.'</td><td>'.$shop->cash_total.'</td></tr>';
}
else {
echo '</tbody>';
echo '<thead><tr><th colspan="2">'.$shop->shop.'</th></tr></thead>';
echo '<tbody>';
echo '<tr><td>'.$shop->shop_product.'</td><td>'.$shop->cash_total.'</td></tr>';
}
$shop_id = $shop -> shop_id;
}
$count++;
}
echo '</tbody>';
echo '</table>';

Related

PHP Group sql query under the same title

I am trying to do a restaurant site where the people can see the menu.
I have a table that looks like this:
And now I want to output this data according the title:
Pizza
Ham & Cheese $150
Onion & Cheese $120
Salad
Caesar $70
Tomate & Olives $60
Dessert
Icecream $110
Vanilla Cake $90
-
Well at the future the menu_title can be changed by the client... That means the title need to be retrieved also from the database.
Here is the code I am trying but I don't have idea how to add the content below the title:
<?PHP
$sql_product="SELECT * FROM cc_restaurants_menu WHERE menu_asoc='$asoc' AND menu_type='product' GROUP BY menu_title";
$stmt_product = $conn->prepare($sql_product);
$stmt_product->execute();
$result_product = $stmt_product->setFetchMode(PDO::FETCH_ASSOC);
if($result_product > 0) {
while($row = $stmt_product->fetch()) {
echo '<h3>'. $row['menu_title'] .'</h3><br><p>'. $row['menu_product'] .'</p>';
}
}
?>
But this code only output the title and the first row :S
Any idea?
EDIT
I got 2 answer correct:
OPTION 1
$sql_product="SELECT * FROM cc_restaurants_menu WHERE menu_asoc='$asoc' AND menu_type='product'";
$stmt_product = $conn->prepare($sql_product);
$stmt_product->execute();
$result_product = $stmt_product->setFetchMode(PDO::FETCH_ASSOC);
if($result_product > 0) {
while($row = $stmt_product->fetch()) {
$menuArr[$row['menu_title']][] = '<p>'. $row['menu_product'] . ''. $row['menu_product_price'] . ''. $row['menu_product_desc'] .'</p>';
}
foreach($menuArr as $menuTitle => $productArr){
echo '<h3>'. $menuTitle .'</h3></br>';
foreach($productArr as $key =>$productname){
echo '<p>'. $productname .'</p>';
}
}
}
OPTION 2
$sql_product="SELECT * FROM cc_restaurants_menu WHERE menu_asoc='$asoc' AND menu_type='product' ORDER BY menu_title";
$stmt_product = $conn->prepare($sql_product);
$stmt_product->execute();
$result_product = $stmt_product->setFetchMode(PDO::FETCH_ASSOC);
$title = "";
while ($row = $stmt_product->fetch()) {
if ($row['menu_title'] != $title) {
echo '<h3>'.$row['menu_title'].'</h3><br>';
$title = $row['menu_title'];
}
echo '<p>'.$row['menu_product'].'</p><p>'.$row['menu_product_price'].'</p>';
}
Please try this
$sql_product="SELECT * FROM cc_restaurants_menu WHERE menu_asoc='$asoc' AND menu_type='product'";
$stmt_product = $conn->prepare($sql_product);
$stmt_product->execute();
$result_product = $stmt_product->setFetchMode(PDO::FETCH_ASSOC);
if($result_product > 0) {
while($row = $stmt_product->fetch()) {
$menuArr[$row['menu_title']][] = $row['menu_product'] . " ".$row['menu_price'];
}
foreach($menuArr as $menuTitle => $productArr){
echo '<h3>'. $menuTitle .'</h3>';
foreach($productArr as $key =>$productname){
echo '<p>'. $productname .'</p>';
}
}
}
I would prefer doing this:
Just SELECT * ... ORDER BY menu_title, and then sort it in PHP:
$title = "";
while ($row = $stmt_product->fetch()) {
if ($row['menu_title'] != $title)
echo '<h3>'.$row['menu_title'].'</h3><br>';
$title = $row['menu_title'];
echo '<p>'.$row['menu_product'].'</p>';
}
GROUP BY will return 1 row for each unique value - which is why you are only seeing 1 row.
Option 1
Use this query to output the 'Menu Title' only, passing the Menu Title to a second query inside the loop, to return rows matching the Menu Title.
Option 2
Remove the GROUP BY in your query, loop through the results using 'logic' to only output the menu Title if it is different from the previous Menu Title.

Recursive PHP function gets only first values

I'm having an issue with below code. I'm trying for some time now, and I believe I must be blind and I do not see something obvious. Can you point at this obvious thing?
Function ought to get all categories and it's names. Takes IDs correctly, but names only for first category and first subcategory.
function collect($id, $current = null) {
global $db_1;
$s = "SELECT category.id as id, category_i18n.name as name from category,category_i18n WHERE category.parent_id= '$id' AND category.visible = '1' AND category_i18n.culture='en' AND category.id = category_i18n.id ORDER BY category.order_asc ASC";
$r = mysql_query($s, $db_1);
$row = mysql_fetch_array($r);
$children = array();
if (mysql_num_rows($r) > 0) {
while ($row) {
$children['name'] = $row['name'];
$children[$row['id']] = collect($row['id']);
}
}
else
{
$children['name'] = $row['name'];
}
return $children;
}
EDIT:
EDIT2:
After changes I'm getting array like this:
array(3) {
["name"]=>
string(9) "Cat"
["id"]=>
string(5) "10404"
["children"]=>
array(3) {
["name"]=>
string(10) "Subcat"
["id"]=>
string(5) "10410"
["children"]=>
bool(false)
}
}
I think it is not problem with mysql query, as in phpmyadmin it works and shows all data properly...
UPDATED :
It seems that you have only 1 level of subdirectory. Your function does this :
1) First it fetches the name and id of the given category.
2) It uses the obtained id to fetch the name of the subcategory which has parent_id = the previously fetched id.
3) Here comes the problem. Due to recursion it again calls collect() with the id of this subcategory. But there is no subcategory for this, so it returns null.
That is,
1st Parent (id1) -> Subcategory(id2) -> Subcategory(id2) and so on.
You can use this to get as many levels of categories as you want :
function collect($id, $current = null) {
global $db_1;
$s = "SELECT category.id as id, category_i18n.name as name from category,category_i18n WHERE category.parent_id= '$id' AND category.visible = '1' AND category_i18n.culture='en' AND category.id = category_i18n.id ORDER BY category.order_asc ASC";
$r = mysql_query($s, $db_1);
$temp = array();
if(mysql_num_rows($r) > 0)
{
while($row = mysql_fetch_array($r))
{
$temp[$row['id']]['name'] = $row['name'];
$temp[$row['id']]['children'] = collect($row['id']); //Get further children (Recursive)
if(!$temp[$row['id']]['children']) {continue;} // If FALSE is returned, means that this category has no sub categories. Move onto next one.
}
}
else {return FALSE;} //No rows present, return FALSE
return $temp;
}
This code is not tested. You will get an array in the following format
$parent[parent_id] -> [name]
-> [children] -> FALSE (if subdirectories are not present)
-> [children_id] #1 -> [name]
-> [children]
-> [children_id] #2 and so on.
UPDATE : you were getting only the last result, because I forgot one thing. The $temp[] array was getting overwritten every time in the loop.

How to get recursively all analogs from table by an article?

I've create a simple table of analogs:
+----+-------+-------+
| id | sku_1 | sku_2 |
+----+-------+-------+
| 1 | a1 | abcd |
| 2 | a2 | a3 |
| 3 | a3 | a1 |
+----+-------+-------+
3 rows in set (0.00 sec)
What it mean? It mean that product with article abcd has an analog with article a1, otherwise for example product with article a3 has an analog with article a1.
How to recursively get all the products from this table by a single article?
My solutions is wrong:
// Small Class to get analogs of products
class Analogs {
public function get_analogs($sku)
{
if (!$sku) return false;
$link = mysql_connect('localhost','','');
mysql_select_db('test');
$sku = mysql_real_escape_string($sku,$link);
$query = mysql_query("SELECT * FROM analogs WHERE sku_1='".$sku."' OR sku_2='".$sku."'");
while($analogs[]=mysql_fetch_assoc($query))
continue;
return $analogs;
}
public function MixedAnalogs($sku)
{
if (!$sku) return false;
$link = mysql_connect('localhost','','');
mysql_select_db('test');
$sku = mysql_real_escape_string($sku,$link);
$query = mysql_query("select sku_1 sku from analogs where sku_2 = '$sku' UNION
select sku_2 sku from analogs where sku_1 = '$sku'");
while($analogs[]=mysql_fetch_assoc($query))
continue;
return $analogs;
}
}
$mixed_analogs = AnalogsMix('abcd',$ids=array());
echo "<pre>";
print_r($mixed_analogs);
echo "</pre>";
// Recursive function to get analogs of analog
function AnalogsMix($sku,$ids=array())
{
$class_analogs = new Analogs();
$analogs = $class_analogs->get_analogs($sku);
foreach ($analogs as $analog)
{
$cross = null;
if ($analog['sku_1']==$sku)
{
$cross->sku = $analog['sku_2'];
}
else
{
$cross->sku = $analog['sku_1'];
}
$cross->id = $analog['id'];
if (!in_array($analog['id'],$ids))
{
$ids[] = $analog['id'];
$mixed[] = AnalogsMix($cross->sku,$ids);
}
}
if (isset($mixed))
{
return $mixed;
}
else
{
return false;
}
}
SQL UNION
select sku_1 sku from analogs where sku_2 = $yourid
union
select sku_2 sku from analogs where sku_1 = $yourid
Then you will get in results only ids of analogs.
Here, I suppose you have all your pairs in an array. For example, for your example, you would call analogsOf(array(array("a1", "abcd"), array("a2", "a3"), array("a3", "a1")), "abcd").
The idea is that you build a list of analogs containing initially only the string you are looking for and, every time you find an analog, you add it to the list of analogs and reiterate. You do so until you iterated the whole array of pairs without finding anything new.
function analogsOf(array $pairs, $key) {
$res = array($key); // The result, with only the given key
$i = 0; // Index of the current item
$changed = false; // Have we added an item to $res during that iteration ?
while ($i < count($pairs)) {
$current = $pairs[$i];
foreach ($res as $item) {
if (($current[0] === $item) && (!in_array($current[1], $res)) {
$res[] = $current[1];
$i = 0; // Reiterate as $res changed
}
else if (($current[1] === $item) && (!in_array($current[0], $res)) {
$res[] = $current[0];
$i = 0; // Reiterate as $res changed
}
else {
$i++; // Nothing found here, go to next item
}
}
}
return $res;
}
Note that this code was NOT tested, so there might be a few bugs here and there, but you've got the idea. Also note that I considered you could put the whole database content in an array, but that is probably not possible for obvious reasons, so you will probably have to adapt the code above.
I found a solution for this problem but the main problem in this approach is that.
it can make a loop like abcd->a1,a1->a3,a3->a2,a2->abcd. and it make recursive function endless and php throw an error. so you have to check for that if it is a big project.
in my solution i consider it parent-> child relation. and if a child found make it parent and check again and so on until there is no result.
let abcd is parent and after first execution a1 is child and relation is abcd->a1. but in next call a1 is parent and from first row of table it give a new relation that is a1->abcd and loop is endless.
To prevent checking in same row i use ID of last row from database and it now check row where id != ID (always check other row)
this is function i write, convert it according to your class and store the value in array as you like. I use a string only.
i knew it not a good solution but i works fine.
<?php
mysql_connect('localhost','','');
mysql_select_db('test');
function getSku($sku, $id, $rel = '') {
$query = mysql_query("SELECT * FROM analogs WHERE sku_1 = '$sku' AND id != '$id'" );
if (mysql_num_rows($query)) {
$row = mysql_fetch_assoc($query);
$sku = $row['sku_2']; //PARENT SKU
$id = $row['id']; //LAST ID
$rel .= $row['sku_1']. '-->' . $row['sku_2']. "<br>";
} else {
$query = mysql_query("SELECT * FROM analogs WHERE sku_2 = '$sku' AND id != '$id'" );
if (mysql_num_rows($query)) {
$row = mysql_fetch_assoc($query);
$sku = $row['sku_1']; //PARENT SKU
$id = $row['id']; //LAST ID
$rel .=$row['sku_2']. '-->' . $row['sku_1']. '<br>';
} else {
return (string)$rel; //NOTHING FOUND
}
}
return getSku($sku,$id,$rel);
}
echo $new = getSku('abcd','-1');

Sort PHP - 2 columns with common subheaders

My code does the two columns, like this:
neighborhood 1
restaurant 1
neighborhood 1
restaurant 2
neighborhood 1
restaurant 3
I WANT:
neighborhood 1
restaurant 1
restaurant 2
restaurant 3
$result = mysql_query("SELECT ID,RName,NHood FROM Restaurants ORDER BY NHood ASC, TRIM(LEADING 'The ' FROM RName) ASC",$connect);
$numRows = mysql_num_rows($result);
$middleIndex = (int)(($numRows+1) / 2);
$names = array();
while($row = mysql_fetch_assoc($result)) {
$names[] = $row['RName'];
$id[] = $row['ID'];
$hood[] = $row['NHood'];
}
// print the left column
echo "<table>";
echo "<tr>";
echo "<td width=60%>";
echo "<div id=\"left\">\n";
for($i = 0; $i < $middleIndex; $i++) {
echo $hood[$i];
echo "<p>$names[$i]</p>\n";
}
echo "</div>\n";
echo "</td>";
// print the right column
echo "<td>";
echo "<div id=\"right\">\n";
for($i = $middleIndex; $i < $numRows; $i++) {
echo $hood[$i];
echo "<p>$names[$i]</p>\n";
}
echo "</div>\n";
echo "</tr>";
echo "</table>";
Here's the logic you want (pseduocode):
SELECT
ID,
RName,
NHood
FROM
Restaurants
ORDER BY
NHood ASC, RName ASC
This should return a list of results ordered first by the neighborhood, then by restaurant name.
Next, you'll process those results line-by-line to create a nested array with the data structure you want for your view:
$neighborhoods = array();
foreach($result as $row)
{
// Add each restaurant to a list named for the current neighborhood
$neighborhoods[$row['NHood']][] = $row['RName'];
}
This will produce a data structure like this:
$neighborhoods = array(
'neighborhood1' => array(
'restaurant1',
'restaurant2',
'restaurant3',
),
'neighborhood2' => array(
'restaurant1',
'restaurant2',
),
)
Which you will then use by doing this:
foreach($neighborhoods as $neighborhood => $restaurants)
{
echo $neighborhood;
foreach($restaurants as $restaurant)
{
echo $restaurant;
}
}
If your list is really large and you're worried about memory the implementation is a bit different but the logic is the same. This technique is faster but it's a bit harder to read and maintain because presentation and data layer logic are all mixed together:
$currentNH = null;
while($row = fetch_row($results))
{
// Detect when the neighborhood changes
if($currentNH != $row['NHood']) {
echo $row['NHood'];
}
echo $row['RName'];
}

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