简体   繁体   中英

MYSQL query problem - can't figure it out

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

  • Hp
  • Sony
  • Acer

HDD

  • Western DIgital
  • Seagate
  • ETC

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

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).

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 eg (this is psedocode below)

$lastInfoCatName = $row['name']; 
while ($row != null)
{
if ($lastInfoCatName != $row['name']
{
$lastInfoCatName = $row['name']
//work on creating the table
}

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

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"

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...

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! :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM