Reputation: 2930
Hy, i have a big question ... it may sound simple but actually it's very complicated
I have two mysql tables :
info_cat (id, name)
info_subcat (id, id_info_cat, name)
I want to show the user the info_cat.name
followed by info_subcat.name
but the problem is that info_cat.name
i want to appear just one time.
Something like this:
Laptop
HDD
So normaly i will query like this (old fashioned)
$query = mysql_query("SELECT * FROM info_cat");
while ($row = mysql_fetch_assoc($query)) {
$id_info_cat = $row['id'];
echo $row['name'];
$query2 = mysql_query("SELECT * FROM info_subcat WHERE id_info_cat = '$id_info_cat'");
while($row2 = mysql_fetch_assoc($query2)) {
echo $row2['nume'];
}
}
and i have while within while
.
My question is how can i use only a query to acomplish this (i think with JOIN) ??
I have tried the following command :
SELECT info_cat.name, info_subcat.name AS name2, info_subcat.id FROM info_cat, info_subcat WHERE info_cat.id = info_subcat.id_info_cat;
but can't figure it out how to manipulate data because it will output :
name name2 id
Laptop Acer 1
Laptop HP 2
Laptop Sony 3
HDD Western Digital 4
HDD Seagate 5
HDD ETC 6
and i just want to echo Laptop one time and HDD one time followed by its subcat names. How can i do that ?
Pleaseee ....
Thank you
Upvotes: 1
Views: 104
Reputation: 265605
there's nothing wrong with having nested while loops, when they describe the problem perfectly (a list within a list). if however, you want to avoid nested while loops at all costs, you can do the following:
$query = mysql_query("
SELECT ic.name ic_name, isc.name isc_name
FROM info_cat ic
LEFT JOIN info_subcat isc
ON ic.id = isc.id_info_cat
ORDER BY ic_name ASC");
$last_cat = '';
while ($row = mysql_fetch_assoc($query)) {
if($row['ic_name'] != $last_cat) {
echo $row['ic_name'];
$last_cat = $row['ic_name'];
}
echo $row['name'];
}
it should be possible to write the above query without the ORDER BY
statement, which gains you a little bit of performance. using ORDER BY
is a little bit more explicit and guarantees (the SQL standards do not dictate a certain ordering of rows, could be anything) the correct ordering and output of the result set (although mysql usually does what you expect).
Upvotes: 2
Reputation: 191789
There are a couple of ways to do this. For the sake of completion, I'll list both.
Method #1
$query = <<<SQL
SELECT
ic.name catname
, is.name subcatname
FROM
info_cat ic
JOIN info_subcat is ON (ic.id = is.info_cat_id)
SQL;
$result = mysql_query($query);
$cats = array();
while ($row = mysql_fetch_object($result)) {
if ( ! isset($cats[$result->catname]) ) {
$cats[$result->catname] = array();
}
$cats[$result->catname][] = $result->subcatname;
}
foreach ($cats as $catname => $subcats) {
echo "$catname<br /> <ul>";
foreach ($subcats as $subcat) {
echo "<li>$subcat</li>";
}
echo "</ul>";
}
Method #2
$query = <<<SQL
SELECT
ic.name catname,
GROUP_CONCAT(is.name) subcatnames
FROM
info_cat ic
JOIN info_subcat is ON (ic.id = is.info_cat_id)
SQL;
$result = mysql_query($query);
while ($row = mysql_fetch_object($result)) {
echo "$row->name<br /><ul>"
foreach (explode(',', $row->subcatnames) as $subcatname) {
echo "<li>$subcatname</li>";
}
echo "</ul>";
}
Since everyone else is going to suggest it too, you should use PDO and PHPTAL, and when you are creating a table you should give the "id" column a name that references the table such as "icID" and "isID"
Upvotes: 1
Reputation: 3307
SELECT info_cat.name, GROUP_CONCAT(info_subcat.name) AS name2
FROM info_cat, info_subcat
WHERE info_cat.id = info_subcat.id_info_cat
GROUP BY info_cat.name;
conCAT! :)
Upvotes: 0
Reputation: 2293
Try using GROUP BY and GROUP_CONCAT.
SELECT
info_cat.name,
GROUP_CONCAT(info_subcat.name ORDER BY info_subcat.name SEPARATOR ', ')
FROM
info_cat
LEFT JOIN
info_subcat ON (info_car.id = info_subcat.id_info_cat)
GROUP BY
info_cat.id
Upvotes: 1
Reputation: 13517
The result you've posted looks like a mysql result, not the php output according to your script.
Iterating through the main categories, it will echo the name, and it will iterate through its sub categories and echo the sub names and move on.
There's nowhere in your example where it prodcues such an output...
Upvotes: 0
Reputation: 15598
Use group by in your query
SELECT info_cat.name, info_subcat.name AS name2, info_subcat.id FROM info_cat inner join info_subcat on info_cat.id = info_subcat.id_info_cat
group by info_cat.name
order by info_cat.name desc
Then in your while loop, do an if check to see if an info_cat name = last info_cat name and if they both are equal then don't add it otherwise add it e.g. (this is psedocode below)
$lastInfoCatName = $row['name'];
while ($row != null)
{
if ($lastInfoCatName != $row['name']
{
$lastInfoCatName = $row['name']
//work on creating the table
}
Upvotes: 1