My database has the following setup
productid | productname | category id
and I want to output them like so:
category #1
item 1
item 2
item 3
category #2
item 1
item 2
item 3
I used group by the group them together and that works fine, but I want to loop through each group and display the contents of that group. How would I do this?
I'd recommend just a simple query to fetch all the rows, sorted by category id. Output the category only if its value changes from the previous row.
<?php
$stmt = $pdo-> query("SELECT * FROM `myTable` ORDER BY categoryID");
$current_cat = null;
while ($row = $stmt->fetch()) {
if ($row["categoryID"] != $current_cat) {
$current_cat = $row["categoryID"];
echo "Category #{$current_cat}\n";
}
echo $row["productName"] . "\n";
}
?>
This should work:
$categories = array();
$result= mysql_query("SELECT category_id, product_name FROM `table` GROUP BY `catagory_id` ORDER BY `catagory_id`");
while($row = mysql_fetch_assoc($result)){
$categories[$row['category_id']][] = $row['product_name'];
}
// any type of outout you like
foreach($categories as $key => $category){
echo $key.'<br/>';
foreach($category as $item){
echo $item.'<br/>';
}
}
The output you can style yourself. You simply add everything into a multidimensional array with the category id as the first level keys.
EDIT: The resulting array might look like this:
$categories = array(
'cateogy_id_1' => array(
1 => 'item_1',
2 => 'item_2',
...
),
'cateogy_id_2' => array(
1 => 'item_1',
2 => 'item_2',
...
),
....
);
What you want is to order them by the category, not group them.
SELECT * FROM MyTable
ORDER BY category_id, product_id
When you iterate through the list, just output a new header whenever the category_id changes.
This approach does not need the data to be sorted by category_id.
You can use php to group each category together in a nested array.
After this, the data can be easily be displayed in a table, passed to a grap/chart library, etc...
<?php
$stmt = $pdo-> query("SELECT * FROM myTable ORDER BY categoryID");
$categories = []; //the array to hold the restructured data
//here we group the rows from different categories together
while ($row = $stmt->fetch())
{
//i'm sure most of you will see that these two lines can be performed in one step
$cat = $row["categoryID"]; //category id of current row
$categories[$cat][] = $row; //push row into correct array
}
//and here we output the result
foreach($categories as $current_cat => $catgory_rows)
{
echo "Category #{$current_cat}\n";
foreach($catgory_rows as $row)
{
echo $row["productName"] . "\n";
}
}
?>
The easiest way is probably to pull the list of categories, iterate through and pull their attached products. (I.e. several queries.)
For instance (pseudocode):
$result = fetch_assoc("SELECT category_id FROM categories");
foreach($result as $row)
{
echo $row['category_id'];
$result2 = fetch_assoc("SELECT product_id FROM products");
foreach($result2 as $row2)
{
echo $row2['product_id'];
}
}
If you want to do it all in one query you can do something like:
$result = fetch_assoc("SELECT product_id, category_id FROM products p JOIN categories c ON p.category_id = c.category_id ORDER BY c.category_id ASC");
$last = null;
foreach($result as $row)
{
# Output the category whenever it changes
if($row['category_id'] != last)
{
echo $row['category_id'];
$last = $row['category_id'];
}
echo $row['item_id'];
}
Then you can iterate over the result set and pull out the category name whenever it changes.
There may be a more sophisticated, elegant way to write the SQL to do everything before you get it from the database, but I'm not that smart. ;)
Note: Examples use pseudo code. I use a mysql abstraction class that works like:
$db->query("SELECT stuff");
$db->multi_result(); // returns 2d-associative array
I can then foreach($db->multi_result() as $row), which is super lazy and awesome.
I can post the code for the abstraction layer if you like.
$stmt = $dbConnection->prepare("SELECT exam_id, COUNT(report_id) FROM bug_report GROUP BY exam_id; ");
//$stmt->bind_param('s',$exam_id);
$stmt->execute();
$extract = $stmt->get_result();
$count = $extract->num_rows;
if($count){
while($rows = $extract->fetch_assoc()){
$exam_id = $rows["exam_id"];
switch($exam_id){
case "jee_questions":
$jeeBugCount = $rows["COUNT(report_id)"];
break;
case "gate_questions":
$gateBugCount = $rows["COUNT(report_id)"];
break;
}
}
}
Related
I have one table with categories and another table with linkrecords for each category and the table structure looks like this:
categories:
id (int)
name (varchar)
links:
id (int)
link (varchar)
fk_cat_id (int)
Here is how I do now, but know that it is a no go with a query within a query:
$query = "SELECT * FROM categories";
if ($result = $mysqli->query($query)) {
while ($row = $result->fetch_assoc()) {
$catid = $row['cat_id'];
echo 'CatName: '.$row['name'];
echo '<ul>';
$query2 = "SELECT * FROM links WHERE fk_cat_id = $catid";
if ($result2 = $mysqli->query($query2)) {
while ($row2 = $result2->fetch_assoc()) {
echo '<li>'.$row2['link'].'</li>';
}
}
echo '</ul>';
}
}
I guess I have to go to some JOIN method, but not sure how!
Following query will be used to retrieve links with relation to link categories.
Also, It is a good practice to specify fields name in query to retrieve specific columns only instead of *.
SELECT links.id AS link_id, links.link, links.fk_cat_id, categories.name
FROM links
JOIN categories ON categories.id = links.fk_cat_id;
I have two tables
Category:
cat_id
cat_name
Items
items_it
item_name
item_cat
I would like to get this result:
Category->cat_name1
- item_name1
- item_name2
Category->cat_name2
- item_name3
- item_name4
With PHP I would go with something like this:
$query1 = 'SELECT *FROM Category';
foreach($query1 as $cat) {
$query2 = 'SELECT *FROM Items WHERE "item_cat" = $cat';
echo $cat;
foreach($query2 as $item) {
echo $item;
}
}
What is the best approach for this using CODEIGNITER?
Here is the simple example in Codeigniter with your schema:
<?php
$this->db->select('*'); // select all columns
$this->db->from('Category'); // FROM table
$this->db->join('Items', 'Items.item_cat = Category.cat_id'); // INNER JOIN
$query = $this->db->get(); // GET RESULT
?>
For getting result, you can use two approaches, either want to get data in object form or in an array.
In Array, use result_array() method, like:
$result = $query->result_array();
echo "<pre>";
print_r($result); // will print all data in array
In Object, use result() method, like:
$result = $query->result();
echo "<pre>";
print_r($result); // will print all data in object
Now you can sort as you want:
$newArray = array();
foreach ($result as $key => $value) {
$newArray[$value['cat_name']][] = $value; // sort as per category name
}
print_r($newArray); // will print all data against each category.
Now print your required result as:
foreach ($newArray as $key => $value) {
echo $key."<br/>"; // print Category Name
foreach ($value as $final_value) {
echo $final_value['item_name']."<br/>"; // print all items against category
}
}
Query Builder Class explore the documentation this will help you more to understand, how can you utilize the INNER or LEFT join CI.
Using a join:
$this->db->select(*);
$this->db->join('items as i', 'i.item_cat = c.cat_id');
$query = $this->db->get('category as c');
foreach($query->result() as $result){
echo $result->cat_name;
echo $result->item_name;
}
I have 2 tables on my db:
cat (id, catname)
link (id, name, url, cat)
I wanted to loop through the table link and output data by cat, here the actual code but id doesn't work anyway :)
for ($i = 1; ; $i++)
{
$list = $mysqli->query('SELECT * FROM links WHERE category='$i'');
while($row = $list->fetch_assoc()) {
print $row["category"];
print $row["name"].' ';
print $row["url"];
print '<br>';
}
}
$list->free();
Is there a way we can get the id from table cat and use that to loop through the data in table link?
Thanks
No need for so many requests inside the loop. There are JOIN statements in SQL for such cases:
$result = $mysqli->query('SELECT category.name AS cat_name,
links.name,
links.url
FROM category
INNER JOIN links ON links.cat=category.id');
while($row = $result->fetch_assoc()) {
print $row["cat_name"];
print $row["name"].' ';
print $row["url"];
print '<br>';
}
$result->close();
I'm dealing with a junction table for a many to many relationship between products and categories. With this particular function I'm attempting to take in a product_ID variable and get all associated category names in an array. However, with the current setup I'm only getting one category per product ID when I know several have 2. Any thoughts? Also anyone know of a good simple solution to more visually keeping track of M2M relationships in mysql?
//INPUT PRODUCT ID, GET ASSOCIATED CATEGORIES
function productcat($pid) {
global $sql;
$query = "SELECT * FROM Product_Category WHERE Product_ID = '$pid'";
$result = mysqli_query($sql, $query);
$catidarray = array();
while($row = mysqli_fetch_array($result)) {
array_push($catidarray, $row['Category_ID']);
}
foreach($catidarray as $i) {
$query = "SELECT * FROM Categories WHERE Category_ID = '$i'";
$result = mysqli_query($sql, $query);
$namearray = array();
while($row = mysqli_fetch_array($result)) {
array_push($namearray, $row['Name']);
}
}
return $namearray;
}
There is something wrong with your function.
In your second foreach, you put the variable $namearray inside the loop which on every run resets its value to empty array $namearray = array();. Just put that outside the foreach:
//--> put it here
$namearray = array();
foreach($catidarray as $i) {
$query = "SELECT * FROM Categories WHERE Category_ID = '$i'";
$result = mysqli_query($sql, $query);
while($row = mysqli_fetch_array($result)) {
array_push($namearray, $row['Name']);
}
}
And, I just want to make some suggestions on your function. Since you have the junction table, you don't really need to have a separate query for product and category in order to get your desired values from those tables.
Just do the INNER JOIN to maximize the use of your table relations.
Use your junction table Product_Category because that's the real purpose why created that.
SELECT *
FROM Product_Category AS a
INNER JOIN Category AS b
ON a.Category_ID = b.Category_ID
WHERE Product_ID = $pid
In your function, you may try this: havent tested but hope this will give you idea.
//INPUT PRODUCT ID, GET ASSOCIATED CATEGORIES
function productcat($pid) {
global $sql;
$query = "SELECT *
FROM Product_Category as a
INNER JOIN Category as b
ON a.Category_ID = b.Category_ID
WHERE Product_ID = {$pid}";
$result = mysqli_query($sql, $query);
$namearray = array();
while($row = mysqli_fetch_array($result)) {
array_push($catidarray, $row['Name']);
}
return $namearray;
}
Then that's it :)
And by the way, in the latest version of php, mysql_ functions are already deprecated. Much better if you will be going to use PDO or MySQLi.
Check this also: PDO vs. MySQLi
I am using the following MySQL query to generate a table for users in a database. The query is designed to just return one row for each user, even though there are multiple rows for each user. This works fine, however I also need to calculate the number of unique entries for each user, to enter into the table where it states HERE. Do I need to use another query to return the count for all entries, and if so how do I integrate this with the code I already have?
$query="SELECT from_user, COUNT(*) AS num FROM tracks GROUP BY from_user ORDER BY COUNT(*) DESC";
$result=mysql_query($query) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
$user = $row['from_user'];
echo "<tr>";
echo "<td>".$user."</td>";
echo "<td>uploads (**HERE**)</td>";
echo "<td>favourites (count)</td>";
echo "</tr>";
}
?>
</table>
Because you've already created the custom field 'num', you can use that to get the count!
Add the following line after user = ...
$count = $row['num'];
Then you can
echo "<td>uploads ($count)</td>";
It miss your table stucture to know your field name, but, if i well understand your question you can use count + distinct in mysql.
You can check this answer too.
SELECT DISTINCT(from_user) AS user,
COUNT(from_user) AS num
FROM tracks
GROUP BY from_user
ORDER BY num DESC";
For the second problem you can doing a second query, or do a join tracks .
I think, in your case it's easier to you to do se second query inside the loop to get all detail from 'user' result.
$query1="SELECT DISTINCT(from_user), COUNT(*) AS num
FROM tracks
GROUP BY from_user
ORDER BY COUNT(*) DESC";
$query2="SELECT * FROM tracks";
$result1=mysql_query($query1) or die(mysql_error());
$result2=mysql_query($query2) or die(mysql_error());
$user_array = array();
while ($row = mysql_fetch_array($result1)) {
$user = $row['from_user'];
$num = $row['num'];
$uploads_array = array();
while ($sub_row = mysql_fetch_array($result2)) {
if( $sub_row['from_user'] == $user ) {
//for example only due to the unknown structure of your table
$uploads_array[] = array(
"file_name" => $sub_row['file_name'],
"file_url" => $sub_row['file_url']
);
}
}
$user_array[] = array(
"name" => $user,
"num_entry" => $num,
"actions" => $uploads_array
);
}
// now the table with all data is stuctured and you can parse it
foreach($user_array as $result) {
$upload_html_link_arr = array();
$user = $result['name'];
$num_entry = $result['num_entry'];
$all_actions_from_user_array = $result['actions'];
foreach($all_actions_from_user_array as $upload) {
$upload_html_link_arr[] = sprintf('%s', $upload["file_url"],$upload["file_name"]);
}
$upload_html_link = implode(', ',$upload_html_link_arr);
$full_row = sprintf("<tr><td>%s</td><td>uploads : %s</td><td>favourites (%d)</td></tr>", $user, $upload_html_link, $num_entry);
// now just echo the full row or store it to a table for the final echo.
echo $full_row;
}
I hope this help, mike