How do i create a 4 dimensional array from a database - php

I'm trying to figure out how to make this code work. Basically i have used MySQL to fetch an associative array containing multiple values.
example database: database name = Products
----------------------------------------------------------------.
| name | overcategory | category | subcategory |
| Talon | null | stud welding | capacitor discharge |
| cdss m3x40 | studs/bolts | cd-studs | stainless steel |
----------------------------------------------------------------.
I used the sentence SELECT name, overcategory, category, subcategory FROM Products WHERE 1 = 1;
In the actual database there are more entries, but they are not relevant for this question.
The result i want to output as a menu on the left hand side of the screen.
<nav>
<h1> "$overcategory" </h1>
<h2> "$category" </h2>
<h3> "$subcategory" </h3>
$productname
$productname3
<h1> "$overcategory2" </h1>
<h2> "$category2" </h2>
<h3> "$subcategory2" </h3>
$productname2
</nav>
i was thinking of doing this by creating a multidimensional array that would look something like this:
$testArray = array(
''=>array(
'Boltsveiseapparater'=>array(
'Kondensator'=>array(
'Talon',
'LBS-75'
),
'Arc'=>array(
'LBH-410',
'LBH-800'
)
)
),
'Pinner/bolter'=>array(
'CD-pinner'=>array(
'rustfri'=>array(
'cdss m3x35',
'cdss m3x40'
),
'stål'=>array(
'cdms m3x35',
'cdms m6x35'
),
'Alu'=>array(
'cdal m3x10',
'cdal m8x80'
)
),
'Bossinger'=>array(
'Stål'=>array(
'M6x10 5x8',
'M5x12 4x10'
),
'Alu'=>array(
'M6x10 5x8',
'M5x12 4x10'
),
'Rustfri'=>array(
'M6x10 5x8',
'M5x12 4x10'
)
)
)
);
I have no idea how to do this by looping through the results. is there any way of doing this without making a giant array of doom? if not, can someone assist me in decyphering this conundrum.
Thank you in advance.
BM.

You could let mysql sort the result set:
SELECT name, overcategory, category, subcategory FROM Products ORDER BY overcategory,category,subcategory;
Then you can simply loop over the result. Whenever the overcategory, category, subcategory changes you output a new header.

If you sort each of the columns of your results in your SQL query, you can just loop through each result and compare it with the last entry and adjust your output based on that.
SELECT name, overcategory, category, subcategory FROM Products ORDER BY overcategory, category, subcategory, name;
Otherwise, here is one way of handling your nested array:
<?php
echo "\n";
echo "<nav>\n";
foreach ($testArray as $overcategory_name => $category_data) {
echo "\t<h1>$overcategory_name</h1>\n";
foreach ($category_data as $category_name => $subcategory_data) {
echo "\t\t<h2>$category_name</h2>\n";
foreach ($subcategory_data as $subcategory_name => $product_name_data) {
echo "\t\t\t<h3>$subcategory_name</h3>\n";
foreach ($product_name_data as $product_name) {
echo "\t\t\t\t$product_name\n";
}
}
}
}
echo "</nav>\n";

How about -
$res = mysql_query('SELECT name, overcategory, category, subcategory FROM Products WHERE 1 = 1 ORDER BY overcategory,category,subcategory, name;');
$aMenu = array();
while($row = mysql_fetch_assoc($res)) {
$aMenu[$row['overcategory']][$row['category']][$row['subcategory']][] = $row['name'];
}
A more significant issue to be looking into is your table structure. Assuming that the overcategory, category and subcategory are part of a hierarchy then you should only be storing the leaf node to which the product belongs, and that should probably be stored as an integer that is a FK to a categories(id, name, parent_id) table. I tend to opt for nested sets for product catalogs but it depends on the requirements.
Furthermore, it is common for an individual product to be represented in more than one category, in which case you would need to move the category relationship to a join table products_categories(product_id, category_id).
Just a little food for thought.

Related

PHP - Loop through UNION ALL query and add custom text once after the last item per category

I have a union query which joins several categories. I want to include the link after the last item of the category.
The query goes like:
SELECT * FROM table WHERE category = 1 LIMIT 10
UNION ALL
SELECT * FROM table WHERE category = 2 LIMIT 6
UNION ALL
SELECT * FROM table WHERE category = 3 LIMIT 11
... the result is
Item 1 - Category 1
Item 2 - Category 1
Item 3 - Category 1
Item 4 - Category 2
Item 5 - Category 2
Item 6 - Category 3
The output should be like this:
Category 1
- Item 1
- Item 2
- Item 3
Go to category 1
Category 2
- Item 4
- Item 5
Go to category 2
Category 3
- Item 6
Go to category 3
Here is the loop thanks to user #Luuk, but now I would like to include a link after the last item from the category.
$c = "";
foreach ($query as $row)
{
if ($c!=$row['category']) {
echo $row['category'] . "<br>";
$c = $row['category'];
}
echo 'Item name:' . $row['item'] . "<br>";
echo 'Go to category - ' $row['category']; //This needs to be after the last item from the category and should be repeated only once per category change.
}
There are quite a few questions I have regarding this logic:
Are you getting all of this data from the same table, I assume so as you have used the same table name in the question.
Why are you limiting each category? do you only ever want to get that many records for that category? what if there was 7 records for category 2, why would you not want to show the last record?
What do you mean by go to the category? PHP is rendered on the server and therefore cannot perform any extra actions after it has ran. When you say go to the category do you mean open a new page displaying data about this category?
Is the category an ID to another table called "category" that has the information about that category? ( if not it really should be ).
My answer below is assuming the answers to the above questions are 1:Yes; 2:Don't need a limit; 3:Yes, open a new page; 4:Yes. I don't mean any offence but I am assuming from the question your new to Web Development so I will explain each step.
Query:
SELECT t1.item_id, t1.item_name, t2.category_id, t2.category_name FROM `item` t1 INNER JOIN `category` t2 ON t1.category = t2.category_id ORDER BY t2.category_id
Here you're getting all items in the item table and joining them onto the category table, then ordering it by the category_id to make sure they all come back in the order they will be displayed in. You should end up with a list that looks like this:
'item 1', 1, 'category 1';
'item 2', 1, 'category 1';
'item 3', 1, 'category 1';
'item 4', 2, 'category 2';
'item 5', 2, 'category 2';
'item 6', 3, 'category 3';
'item 7', 3, 'category 3';
so on...
the first variable being the item id, the second being the item name, the third being the category id and the forth being the category name
Code:
<?php
$result = //code to run the query;
$previousItem['category_id'] = NULL;
foreach($result as $item)
{
//checking to see if the category has changed
if($previousItem['category_id'] != $item['category_id'])
{
//making sure that were not on the first category
if($previousItem['category_id'] != NULL)
{
//ending the last categories list
echo '</ul>';
//echoing a link to another page which will contain the info about that category making sure to include the category_id within a URL parameter
echo ' Go to category - '.$item['category_name'].'<br>';
}
//echo the category name (I have added a header to make it stand out)
echo '<h4>'.$item['category_name'].'</h4>';
//start the list for this category;
echo '<ul>';
}
//echo out the item
echo '<li>'.$item['item_name'].'</li>';
//set the new previous category for the next loop
$previousItem = $item;
}
//finish everything off after the loop has ran
echo '</ul>';
echo ' Go to category - '.$previousItem['category_name'].'<br>';
?>
Then you would have another file, I have called it 'category.php' that has a URL parameter telling the category page which category it needs to load. On the category.php page the code to grab that ID would look like this:
<?php
//getting the category_id from the URL
$category_id = $_GET['category'];
//building your query based off the category_id requested
$query = sprintf("SELECT * FROM category WHERE category_id = %s", $category_id);
//you would then run this query and display whatever data you wanted to
?>
as the user could change the URL parameter you would definitely need to wrap the $category_id in some sort of security function that strips it of any potential hackers code but for simplicity I have not included that.
Although I am not 100% this answers your question, I hope it provides some explanation as to how you would normally do something like this.

php and mysql dynamic breadcrumps

I have a website that list all food sources; In my db I've made a MySQL table named [foods]
In my page, when the user click the category he gets list of its all children. in my case
food
-- Plants
---- Vegetable
------ Aubergine
------ Broad_bean
------ Broccoli
------ Carrot
---- Fruits
------ Apple
------ Apricot
------ Banana
------ Cherry
------ Clementine
------ Guava
-- Animals
Now, I want to make a dynamic breadcrumbs navigation in the top of my page, something like
Food > Plants > Fruits > Banana
So the user can navigate through them.
I've tried several queries to get this but with no luck.
Every time I get only the first parent of the category only
So if I am in Banana page I only get the Fruits category, nothing deeper.
I know I have to use while loop where cat_parent_id != 0 but I couldn't figure-out how to implement it the right way!
here is a code snippet I've tried
$cat_parent_id = $_REQUEST['cat_id'];
$q = mysqli_query($link, "SELECT * FROM foods WHERE cat_id = $cat_parent_id");
while($r = mysqli_fetch_assoc($q))
{
echo $name = $r['cat_name'];
}
I really appreciate your help in this regards
Thanks in advance...
u have to use recursive function. means check
for ex:
function show_breadcumb($cat_id)
{
$q = mysqli_query($link, "SELECT * FROM foods WHERE cat_id = $cat_id");
while($r = mysqli_fetch_assoc($q))
{
$name = $r['cat_name'];
$string.= $name .">".$string
}
//check if this category has any parent again call this fucntion
if( has parent ) { show_breadcumb($cat_id) }
else return $string;
}
Means ur loop should continue find category up to first level.

Cross tabulating a query with php

I'm trying to come up with an efficient way of displaying some data but not succeeding at all.
The table is built dynamically from a few tables to show a row of headers with the columns populated showing the results by site e.g:
Site name | Column A | Column B | Column C => column headers continue from DB query
Site A | Result A | Result B | Result C
Site B | Result C | Result B | Result C
Site C | Result C | Result B | Result C
Results keep going vertically.
Here's the query I'm using
$risk_section=$row_risk_category['risksectid'];
mysql_select_db($database_auditing, $auditing);
$qry_selfsites = sprintf("SELECT
tblself.siteid AS selfsite,
tblsite.sitename AS sitename,
tblsite.address AS address,
tblpct.pctname AS pctname,
tblresultsnew.total,
tblresultsnew.auditid AS auditid,
tblriskcategories.risksectid AS risksectid,
tblriskcategories.risksection AS risksection
FROM tblself
LEFT JOIN tblresultsnew ON tblself.auditid = tblresultsnew.auditid
LEFT JOIN tblsite ON tblself.siteid = tblsite.siteid
LEFT JOIN tblpct ON tblsite.pctid = tblpct.pctid
LEFT JOIN tblriskcategories ON
tblresultsnew.risksectid=tblriskcategories.risksectid
WHERE tblsite.pctid IN (SELECT pctid FROM tblreportpcts WHERE
pctreportid='$pctreportid')
AND tblsite.sitetypeid IN (SELECT sitetypeid FROM tblreportsites WHERE
pctreportid='$pctreportid')
AND tblself.year = %s
ORDER BY tblsite.pctid,tblsite.sitename",
GetSQLValueString($yearofrpt, "int"));
$selfsites = mysql_query($qry_selfsites, $auditing) or die(mysql_error());
$totalRows_selfsites = mysql_num_rows($selfsites);
So the question is, is there a way to get the data from the above query (or an adapted version thereof) to build the table dynamically with all the results lining up correctly?
So far, I can only get it to build vertically.
Sorry, edit time (having worked with the answer below, I realised I hadn't got the question worded very well)
What I'm trying to get is a row of column headers from the query (tblriskcategories.risksection AS risksection) These populate horizontally to give the columns names.
Then underneath, the sitename is displayed with the result corresponding to the column header above i.e.
<table>
<tr>
<th>Sitename</th>
<?php while($row_selfsites=mysql_fetch_assoc($selfsites){
//loop through the section headers pulled from the DB (tblriskcategories)
<th><?php echo $row_selfsites['risksection'];//show the section headers?></th>
<?php }
//end header loop then start another loop to show a row for each site pulled
//out by the query and show the relevant results in the correct column
while($row_selfsites=mysql_fetch_assoc($selfsites)) {
//do the vertical drop matching the header rows with the sitenames from tblsite
//and the results from tblresultsnew
?>
<tr>
<td><?php echo $row_selfsites['sitename'];?></td>
<td><?php echo $row_selfsites['total'];
//these need to grow to fit the headers and each site?></td>
<tr>
<?php } //end displayed data loop?>
</table>
The relevant tables structure below:
tblresultsnew resultsid,auditid,risksectid,total
tblriskcategories risksectid, risksection
tblself selfauditid,siteid,auditid
tblsite siteid,sitename
So tblself holds the list of sites we need the data for and the relevant auditid,
tblresultsnew holds the results - the total column - for each risksectid and each auditid eg, one auditid can have approx 8 risksectid's each with corresponding total
tblriskcategories holds the column headings
tblsite holds the site data to make it mean something
I hope this explains the question a little further.
Thanks again for all the help.
Dave
$rows = array(
0 => array('headingA' => 'results1a', 'headingB' => 'results1b', ),
1 => array('headingA' => 'results2a', 'headingB' => 'results2b', ),
2 => array('headingA' => 'results3a', 'headingB' => 'results3b', ),
);
// $rows is spoofing a db result set as an array
//var_dump( $rows );
$first = true ;
$header_row = "START TABLE <br />" ;
$data_rows = "";
foreach( $rows as $row ) {
foreach( $row as $key=>$value ){
if( $first === true ){
$header_row .= "$key | ";
}
$data_rows .= "$value |";
}
if( $first ) $header_row .="<br />";
$data_rows .= "<br />";
$first = false;
}
echo $header_row . $data_rows . "END TABLE";
Gives:
START TABLE
headingA | headingB |
results1a |results1b |
results2a |results2b |
results3a |results3b |
END TABLE
Is that the kind of solution you are after?

sql select all children AND grandchildren from a certain ancestor (root category)

I've got some images in several categories. All categories are in a certain table (let's say tbl_categories). The level of subcategories is between 1 and 10.
I would like to create a query that gives all id's of subcategories (and their subcategories, and so on ...) from a certain root category (which can be a subcategory itself).
Example:
Category 1
subcategory a
Category 2
subcategory b
subsubcategory I
subsubcategory II
subcategory c
If i use category 2, i want subcategories b and c, and subsubcategories I en II as a result.
Sounds fairly easy but i haven't got a clue.
I'm fairly new to writing queries...
Thanks
Try This:
//Parents
$data = mysql_fetch_assoc(mysql_query("select id,name from categories where parent = 0"));
//Childrens
foreach( $data as $key => $row)
{
$data[$key]['childrens'] = mysql_fetch_assoc(mysql_query("select id,name from categories where parent ='".mysql_real_escape_string( $row['id'] )."'"));
//childrens
foreach( $data[$key]['childrens'] as $_key => $_row )
{
$data[$key]['childrens'][$_key]['childrens'] = mysql_fetch_assoc(mysql_query("select id,name from categories where parent ='".mysql_real_escape_string( $_row['id'] )."'"));
}
}
//Print Array
print_r( $data );

PHP Show Products within the child categories... custom shopping cart

I have a shopping cart im making. And I'm stumped at finding out how I can load products within multi-level categories that are children of the category im looking at.
For example:
-Cars
Subarus (Legacy, Outback) - Holden (Commodore, Calais) - Toyota (Corolla, Camry)
If i'm looking in the cars category, i can select the child category but I cant view the actual products that are in those sub-categories. Is there any way I can do this? even if you can have unlimited levels of categories like "ROOT > Cars > Sedan > Subaru's..."?
Each product has a category ID which it relates to a category. Each category has its unique ID and a 'parent' id which has the ID of the category that it's a child of.
I think what you'll need to do is build up a list of category IDs to then construct an IN clause for your sql. Let's say you have the following category structure:
Cars (id:1)
Toyota (id:2, parent:1)
Mini (id:3, parent:2)
Corolla (id:4, parent:3)
Holden (id:5, parent:1)
Sports (id:6, parent:5)
HSV (id:7, parent:6)
To get all descendants of a category, you'll need to loop through the parent/child structure with something like this:
/**
* I'm only writing pseudocode here btw; I haven't tested it.
* Obviously you'll need to fire the SQL commands...
*/
function getKids ($id, $found = array())
{
array_push ($found, $id);
$nbrKids = "select count(id) from category where parent_id = $id";
if ($nbrKids > 0) {
$newKids = "select id from category where parent_id = $id";
foreach ($newKids as $kid) {
return getKids ($kid, $found);
}
}
else {
return $found;
}
}
Then call getKids() like this, where $id is your category id:
$ids = getKids($id);
$ids is an array of all the categories you are interested in. You could then use join() to construct an SQL string:
$sql = "select * from cars where category_id in (" . join (",", $ids) . ")";
For correctness, you should check that $ids has at least 1 member first, otherwise your SQL query will be invalid.
[edit: actually in the above code, $ids will always have at least one member: the initial id. However, the code doesn't verify the initial id is a valid category_id. ]

Categories