PHP MySQL Display One Time - php

I have two tables called categories and topics.
categories has columns category_id and category_title. topics has columns topic_id, topic_title, and category_id.
I currently display the columns like so:
$result = mysqli_query($db_server, 'SELECT c.category_title, t.topic_title FROM categories c JOIN topics t on c.category_id = t.category_id');
while ($row = mysqli_fetch_array($result))
{
$category_title[] = $row['category_title'];
$topic_title[] = $row['topic_title'];
}
<?php
foreach ($category_title as $category_title):
echo htmlspecialchars($category_title, ENT_QUOTES, 'UTF-8');?><br />
<?php endforeach; ?>
<?php
foreach ($topic_title as $topic_title):
echo htmlspecialchars($topic_title, ENT_QUOTES, 'UTF-8');?><br />
<?php endforeach; ?>
This will display as:
Category 1
Category 1
Category 2
Topic 1
Topic 2
Topic 3
Topic 1 and 2 are assigned to Category 1, while Topic 3 is assign to Category 2.
How can I have Category display once if there are multiple topics assign to it, such as:
Category 1
Category 2
Topic 1
Topic 2
Topic 3
Please no classes and objects examples. I'm not learning that yet.

You can run query two time first for category then run new query to selected topic according to category as below:
<?php
$result = mysqli_query($db_server, 'SELECT c.category_id,c.category_title FROM categories as c');
$recordArray=array();
while ($row = mysqli_fetch_array($result))
{
$category_id = $row['category_id'];
$recordArray[$category_id] = $row['category_title'];
//Query For Topic
$getTopic = mysqli_query($db_server, "SELECT t.topic_title FROM topics as t WHERE t.category_id='".$category_id."'");
while ($getRow = mysqli_fetch_array($getTopic))
{
$recordArray[$category_id]['topic'][] = $getRow['topic_title'];
}
}
print"<pre>";
print_r($recordArray);
?>

Use group_concat, here is an example http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat

You can modify your SQL query adding a "GROUP BY" statement. It would be something like:
SELECT c.category_title, t.topic_title FROM categories c JOIN topics t on c.category_id = t.category_id GROUP BY c.category_id
You can find here a clear example of using GROUP BY.

written off my head not tested:
first I dunno why don't you use it inside one loop, it will perform faster but it will swap the output
$result = mysqli_query($db_server, 'SELECT c.category_title, t.topic_title FROM categories c JOIN topics t on c.category_id = t.category_id');
$oldCategory='';
while ($row = mysqli_fetch_array($result)) {
if ($oldCategory!=$row['category_title']) {
echo htmlspecialchars($row['category_title'], ENT_QUOTES, 'UTF-8').'<br />';
$oldCategory=$row['category_title'];
}
echo htmlspecialchars($row['topic_title'], ENT_QUOTES, 'UTF-8').'<br />';
}
or this will not swap the output:
$result = mysqli_query($db_server, 'SELECT c.category_title, t.topic_title FROM categories c JOIN topics t on c.category_id = t.category_id');
$oldCategory='';
$catStr='';
$topStr='';
while ($row = mysqli_fetch_array($result)) {
if ($oldCategory!=$row['category_title']) {
$catStr.=htmlspecialchars($row['category_title'], ENT_QUOTES,'UTF-8').'<br />';
$oldCategory=$row['category_title'];
}
$topStr.=htmlspecialchars($row['topic_title'], ENT_QUOTES, 'UTF-8').'<br />';
}
echo $catStr.$topStr;

Related

How to optimize nested query with PHP and MySqli?

I have this code, that fetches data from two tables in MySQLi.
It first has to get the title, description, status and project_id from table 1, and then get the name from table 2 using the id from table 1.
Is there a better/faster way to do this? I have about 600 rows in the tables, and it takes about 5 sec to run this query. I will also add that this example is a bit simplified, so please don't comment on the db-structure.
<?php
$results = $connect()->db_connection->query(
'SELECT title, description, status, project_id
FROM table
WHERE created_by ='.$user_id
);
if ($results) {
while ($result = $results->fetch_object()) {
$res = $connect()->db_connection->query(
"SELECT name FROM projects WHERE id = ".$result->project_id
);
if ($res) {
while ($r = $res->fetch_object()) {
echo $r->name;
}
}
echo $result->title;
echo $result->status;
}
}
?>
Use Query:
SELECT title,description,status,project_id
FROM table tb
inner join projects pr on pr.id = tb.project_id
WHERE created_by = $user_id
Try to use JOIN in your query.
You can find examples and description of this command here: http://www.w3schools.com/sql/sql_join.asp
Check out also this infographics:
http://www.codeproject.com/KB/database/Visual_SQL_Joins/Visual_SQL_JOINS_orig.jpg
You can use JOIN on project_id:
$results = $connect()->db_connection->query('SELECT t.title title,t.description,t.status status,t.project_id, p.name name FROM `table` t JOIN projects p ON p.id= t.project_id WHERE t.created_by ='.$user_id);
if($results){
while($result = $results->fetch_object()){
echo $result->name;
echo $result->title;
echo $result->status;
}
}
tables have aliases here - t for table and p for projects.
Also to make it faster, add index to project_id in table table, if you haven't done it yet:
$connect()->db_connection->query('ALTER TABLE `table` ADD INDEX `product_id`');

Is it faster to use one large query or several smaller queries?

I've been pondering this for some time and thought I would ask some people that are knowledgeable of MySQL and even PHP. Let's say you have a query that gets dynamic information about an article. You also have several tables associated with the articles such as comments and categories. Let's say that on a page of article results you would like to get information such as the number of comments and what category the article is in. Which method would load faster?
One Large Query:
$query = "
SELECT
a.article_id, a.title, a.description, a.category_id
com.comment_id, com.article_id, COUNT(com.article_id) AS num_comments
cat.category_id, cat.title AS cat_titleca
FROM articles AS A
LEFT JOIN categories AS cat ON (a.category_id = cat.category_id)
LEFT JOIN comments AS com ON (a.article_id = com.comment_id)
GROUP BY a.article_id
ORDER BY a.article_id DESC
LIMIT 10";
if($query = mysql_query($query)){
if(mysql_num_rows($query) > 0){
while($article=mysql_fetch_assoc($query)){
echo $article['title'].' has '.$article['num_comments'].' comments and is in the category '.$article['cat_title'].'.';
}
}
}
Or to use several smaller queries:
<?php
$query_articles = "
SELECT
article_id, title, description, category_id
FROM articles
ORDER BY article_id DESC
LIMIT 10";
if($query_articles = mysql_query($query_articles)){
if(mysql_num_rows($query_articles) > 0){
while($article=mysql_fetch_assoc($query_articles)){
$query_comments = "
SELECT
comment_id, article_id
FROM comments
WHERE article_id = ".$article['article_id']."
ORDER BY comment_id";
if($query_comments = mysql_query($query_comments)){
$num_comments = mysql_num_rows($query_comments);
}
$query_cat = "
SELECT
category_id, title
FROM categories
WHERE category_id = ".$article['category_id']."
LIMIT 1";
if($query_cat = mysql_query($query_cat)){
if(mysql_num_rows($query_cat) > 0){
$cat = mysql_fetch_assoc($query_cat);
}
}
echo $article['title'].' has '.$num_comments.' and is in the category '.$cat['title'].'.';
}
}
}
A single query is faster of course, why don't you do benchmark
$time = microtime(true);
//code here
$elapsed = microtime(true) - $time;
echo 'Elapsed time = '.$elapsed;

Building a Mysql table-tree using query instead of loops in PHP

I have a category tree that contains up to 3 levels of children-categories, like this:
houseproducts->livingroom->sofas->twoseats
houseproducts->livingroom->sofas->threeseats
houseproducts->livingroom->sofas->fourseats
So for each sublevel, I do a SELECT based on the mothers category-id. This is done in a PHP-loop like the code below, but I guess it could be done in one single Mysql-query, for better performance. I have tried different JOINS but find it really difficualt. Any advice will be highly appreciated.
function build_category_tree()
{
$cat = array();
// main category loop
$r1 = mysql_query("SELECT cat_id,cat_name FROM categories WHERE cat_mother=0 OR cat_mother='' ORDER BY cat_name");
while ($row=mysql_fetch_assoc($r1))
{
$cat[$row['cat_id']] = $row['cat_name'];
// check for subcategories
$r2 = mysql_query("SELECT cat_id,cat_name FROM categories WHERE cat_mother='".$row['cat_id']."'");
while ($subrow=mysql_fetch_assoc($r2))
{
$cat[$subrow['cat_id']] = ' - '.$subrow['cat_name'];
// check if there is subcats for the current subcategory
$r3 = mysql_query("SELECT cat_id,cat_name FROM categories WHERE cat_mother='".$subrow['cat_id']."'");
while ($subrow2=mysql_fetch_assoc($r3))
{
$cat[$subrow2['cat_id']] = ' -- '.$subrow2['cat_name'];
// check if there is subcats for the current subcategory
$r4 = mysql_query("SELECT cat_id,cat_name FROM categories WHERE cat_mother='".$subrow2['cat_id']."'");
while ($subrow3=mysql_fetch_assoc($r4))
{
$cat[$subrow3['cat_id']] = ' --- '.$subrow3['cat_name'];
}
}
}
}
return $cat;
}
I would read your entire table into an array and segment that array by the mother's keys
Try this:
SELECT l1.cat_id AS l1_cat_id
,l1.cat_name AS l1_cat_name
,l2.cat_id AS l2_cat_id
,l2.cat_name AS l2_cat_name
,l3.cat_id AS l3_cat_id
,l3.cat_name AS l3_cat_name
,l4.cat_id AS l4_cat_id
,l4.cat_name AS l4_cat_name
FROM categories AS l1
JOIN categories AS l2
ON l2.cat_mother = l1.cat_id
JOIN categories AS l3
ON l3.cat_mother = l2.cat_id
JOIN categories AS l4
ON l4.cat_mother = l3.cat_id
WHERE l1.cat_mother=0 OR l1.cat_mother=''
ORDER BY l1_cat_name, l2_cat_name, l3_cat_name, l4_cat_name

What is the best way to get Category-info and Article-info at same time from mysql/php?

I am building a simple newspaper-site, due to schoolwork. I have two tables in my database.
Categories
[CategoryID, CategoryName, ParentID (which points to cat.id)]
Article
[ArticleID, Heading, Teasertext, Content, Date, Category(which is foreign key to CategoryID)]
On the first page im pulling out the latest articles written, and below each article has to have a link to the article (which is based on index.php?name=CategoryName&parent=ParentID).
I need to withdraw the relevant info about CategoryName and ParentID from the Category-info in Articles-table.
Im stuck on how to combine the two queries in to one. Im wondering if you have any idea´s on how to solve it?
This is what I got.
function display_articles($link)
{
$result = mysqli_query($link, "SELECT * FROM Article ORDER BY Date DESC");
if (!$result)
{
$error = 'Error fetching Articles: ' . mysqli_error($link);
exit();
}
while ($row = mysqli_fetch_array($result))
{
$Heading[] = $row['Heading'];
$Teasertext[] = $row['Teasertext'];
$Date[] = $row['Date'];
}
if (isset($Heading))
{
for ($i=0; $i<count($Heading); $i++)
{
echo '<div class="frontpage"><h2>' .htmlspecialchars($Heading[$i], ENT_QUOTES, "UTF-8"). '</h2>';
echo htmlspecialchars($Date[$i], ENT_QUOTES, "UTF-8");
echo '<p class="Teasertext"> ' .htmlspecialchars($Teasertext[$i], ENT_QUOTES, "UTF-8"). '</p></div>';
echo '<a href="index.php?name='
}
}
}
Use a join:
SELECT
a.*, c.CategoryName, c.ParentID
FROM
Article AS a
INNER JOIN Category AS c on a.category = c.categoryId
ORDER BY a.Date DESC
Your query should be like this:
SELECT
a.*,c.*
FROM
Article a LEFT JOIN
Categories c on (a.category=c.categoryid)
ORDER BY
a.Date DESC

PHP MYSQL showing posts with comments

I dont know where to start let me make it simple...
I have 2 tables posts and comments, posts consisting 2 fields: id and post_name and comments consisting of 3 fields: id, comment and post_id. I have some posts with few comments on those.
How can I display all posts with the related comments using while loop?
Thanks in advance....
SELECT `p`.`post_name`, `c`.`comment`
FROM `posts` AS `p`
JOIN `comments` AS `c` ON(`p`.`id` = `c`.`post_id`)
GROUP BY `p`.`id`;
This will give you a resultset where each row contains a comment and the name of the post that goes with that comment.
You'll need a nested loop to accomplish what you are looking for. Here's a sample that should help get you started.
$posts_result = mysql_query("SELECT your, columns FROM poststable");
if(mysql_num_rows($posts_result) > 0){
$comments_result = mysql_query("SELECT comments FROM commentstable WHERE comments.post_id = $post_id");
while($post = mysql_fetch_array($posts_result){
// print post details
if(mysql_num_rows($comments_result) > 0){
while($comment = mysql_fetch_array($comments_result)) {
// print comment details
}
} else {
// print comments default for when there are no comments
}
} // End posts while
} else {
// print no posts found
}
Run query
select * from posts p, comments c where p.id=c.post_id group by p.id;
and iterate over the results and display them as you want.
This should get you started:
$sql = 'SELECT c.*, p.post_name FROM posts p INNER JOIN comments c ON p.id = c.post_id ORDER BY p.id DESC, c.post_id DESC';
$result = mysql_query($sql);
$previous_post = 0;
while ($data = mysql_fetch_assoc($result)) {
if ($previous_post != $data['post_id']) {
echo '<h1>' . $data['post_name'] . '</h1>';
$previous_post = $data['post_id'];
}
echo '<p>' . $data['comment'] . '</p>';
}

Categories