How to display all comments per article (PHP & SQL)? - php

So I have two tables, article and comments (which has one-to-many relationship (1 article - many comments)). This is how the table is structured:
Articles - id (prikey), title, publicationDate, content
Comments - com_id (prikey), author, comment, id (foreign key)
I used this to query the two tables:
SELECT * FROM articles as a INNER JOIN comments as c ON a.id = c.id
Previously, I was only displaying the articles table using this:
<?php
while($row = mysqli_fetch_array($query)) {
echo "
<div id='article'>
<header>
<hgroup>
<h2>".$row['title']."</h2>
<h4>Posted on ".$row['publicationDate']."</h4>
</hgroup>
</header><p>".$row['content']."</p></div>";
}
?>
This displays all articles (with date, title, content, etc.). Now there are comments. How do I edit the php code (or if my query is incorrect, how to write the query), so that it shows all articles and all comments per article as in:
Article One
-- Comment 1
-- Comment 2, etc.
Article Two
-- Comment 1
-- Comment 2, etc.

An alternative would be to split the query into two.
The first would bring back the articles you want...
SELECT * FROM article;
Once you have those, you can get all the IDs and use something like the following
SELECT * FROM comments WHERE article_id IN (".$list.");
This restricts the MySQL queries to 2 whilst getting all the data you need. After this loop around the article data, and in that loop, loop around the comments data.
This also means that, unlike using GROUP_CONCAT, you will also have author data to use.
It's not a very eloquent solution, but should work.

Query:
SELECT c.author, c.comment,
a.id article_id, a.title, a.publicationDate, a.content
FROM comments c
RIGHT JOIN articles a
ON c.id = a.id
PHP:
<?php
$lastArticleId = 0;
$isNewArticle = false;
while($row = mysqli_fetch_array($query)) {
$isNewArticle = ($lastArticleId != $row['article_id']) ? true : false;
if($isNewArticle) {
$lastArticleId = $row['article_id']; ?>
<div class="article">
<header>
<hgroup>
<h2><?php echo $row['title']; ?></h2>
<h4>Posted on <?php echo $row['publicationDate']; ?></h4>
</hgroup>
</header>
<p><?php echo $row['content']; ?></p>
</div>
<?php
}
if($row['comment'] != '') { ?>
<p><strong><?php echo $row['author']; ?></strong> - <?php echo $row['comment']; ?></p>
<?php
} ?>
<?php
} ?>

Use something like
SELECT a.article
,GROUP_CONCAT(CONCAT('<p>', c.comment, '</p>') SEPARATOR "\n") as comments
FROM
article a
INNER JOIN comment c ON (c.article_id = a.id)
WHERE a.id = '12454';
You may have to fiddle a bit with the separator.
See: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
Do note however:
The result is truncated to the maximum length that is given by the group_concat_max_len system variable, which has a default value of 1024. The value can be set higher, although the effective maximum length of the return value is constrained by the value of max_allowed_packet. The syntax to change the value of group_concat_max_len at runtime is as follows, where val is an unsigned integer:
SET [GLOBAL | SESSION] group_concat_max_len = val;
See here how to change max_allowed_packet
http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_max_allowed_packet

Look into MySQL GROUP_CONCAT which will return a comma delimited list of items. You can then explode that for your comments section.

once a person will comment on a article insert article id with that comment and later get them accordingly something like this
once a person will select an article to read send article id in the $_GET to your article page so you can excess the article id.Once a person will comment on that article insert it as follows
$sql = mysql_query("INSERT INTO comments_table (subject,article_id,comments) VALUES ('$subject','$_GET['id']','$comments')");
and later when you pulling them do it the same way as you have the article id in the $_GET
you can access it run a query like this
$fetch = mysql_query("SELECT * FROM comments WHERE article_id = $_GET['id'] ORDER BY id DESC") or die(mysql_error());
Hope this will work

Related

How would I select and display the most recently added rows from a SQL table?

I am making an extremely basic posting system, and I cant seem to figure out how to get the most recent rows from a certain table. I have tried other solutions offered here, but my posts were randomly placed. How would I accomplish this? My code is below.
function load_posts(){
$posts_sql = "SELECT * FROM posts";
$posts_result = Phoenix\Database\Database::$database->query($posts_sql);
while($row = $posts_result->fetch_assoc()){
$posts_display = '
<div class = "card" style = "width:500px">
<div class = "card-body">
<div class = "card-title">'. $row['username'] .'</div>
<p>'. $row['content'] .'</p>
</div>
</div>
';
echo $posts_display;
}
}
Again, I want the posts to be displayed from most recent, to old.
You need to have information in each row that captures this information. The most common suspects are:
an auto-incrementing id
a creation date
Then you just ask the database to sort the results. For instance, if post_id is an auto-incremented id:
select p.*
from posts p
order by p.post_id;
SELECT * FROM TableName ORDER BY id DESC
// order by should be with primary key

how to show separate column unique values with SQL GROUP BY clause

Alright, I can't bash my head at this anymore tonight. Thought I would pose the question. Maybe there's a simple answer I have not come across yet.
I have a number of related tables in PHPMyAdmin: pubtopics, pubtypes, and pubtitles.
Pubtitles is the main table (table 1), pubtopics is a simple list assigning a number to a topic (table 2), and pubtypes is another simple list assigning a number to a publication type (table 3).
I'm trying to create a page that lists every publication by type (list of all pubs in table 3), but also shows the multiple topics (table 2) that may be assigned to a unique pubtitle (table 1), and have each of those topics (table 2) link to publications listed by that topic.
The data for pubtopics looks something like this:
pubtopics
What I'm looking for is a line like this:
June 15, 2016 | Comparative Data Report | Education | Fiscal Affairs
Where the date is a link, the pub type is a link, and each of the concatenated issues is a unique link.
When I try to list all the publications for a specific publication type, all I can generate so far is either a list with multiple duplicate entries (because one may address several topics). I've tried group_concat and group by, but that doesn't allow me to have an individual link for each topic.
I've played around with explode and arrays, but it's a bit beyond my know-how. Any brilliant solutions?
Code looks like:
elseif (isset($_GET['type'])) {
$var3_getDisplay4 = $_GET['type'];
$query_getDisplay = sprintf("SELECT
DATE_FORMAT(publicationsnew.date, '%%Y') AS archive,
DATE_FORMAT(publicationsnew.date, '%%M %%e, %%Y') AS pubdate,
pub_type.number AS typelink,
pub_type.type AS pubtype,
GROUP_CONCAT(categories.category_name ORDER BY categories.category_name SEPARATOR ' | ') AS category,
categories.category_id AS catlink,
publicationsnew.title,
publicationsnew.author,
publicationsnew.imagelink,
publicationsnew.description
FROM
pub_cat
LEFT JOIN publicationsnew ON (pub_cat.pub_id = publicationsnew.pub_id)
LEFT JOIN categories ON (pub_cat.category_id = categories.category_id)
LEFT JOIN pub_type ON (publicationsnew.type = pub_type.number)
WHERE pub_type.number = %s
GROUP BY publicationsnew.pub_id
ORDER BY publicationsnew.date DESC",
GetSQLValueString($var3_getDisplay4, "text"));
and in the body:
<?php do { ?>
<h2><?php echo $row_getDisplay['pubdate']; ?> | <?php echo $row_getDisplay['pubtype']; ?> |
<a href="test.php?topic=<?php echo $row_getDisplay['catlink']; ?>">
<?php echo $row_getDisplay['category']; ?>
</a>
</h2>
<p class="pubtitle"><?php echo $row_getDisplay['title']; ?></p>
<?php echo ($row_getDisplay['author']); ?>
<?php echo ($row_getDisplay['imagelink']); ?>
<div class="pubdescription"><?php echo ($row_getDisplay['description']); ?></div>
<div class="clear"></div>
<hr>
<?php } while ($row_getDisplay = mysql_fetch_assoc($getDisplay)); ?>
Burned out for the day. To be continued...

How can I combine 2 seperate MySQL queries in a foreach statement

Say I have some posts and those posts contain comments, some posts have more than 1 comment and others have only 1 comment.
I would have to grab all the data from the user from that post and the user info from the person who commented on that post. Now say i have to echo out all that data. I would first go with a foreach and another foreach inside sorta like this!
So I made 2 MySQL queries $postinfo containing all userinfo for the post and the second MySQL query $comments containing all the comments for each post.
Now this works but I was wondering if there is a better way, better practice? The reason I want to fix this, is because I want to AJAX the comments so they can auto update and this way seems to sluggish
<?php
foreach ($postinfo as $info) {
echo "<div id='container'>
<div id='userpost'>
<p>" . $info['firstn'] . "</p>
<p>" . $info['posttext'] . "</p>
</div>";
foreach ($comments as $comment) {
echo "<div id='comments'>
<p>' . $comment['firstn'] . '</p>
<p>' . $comment['commenttext'] . '</p>
</div>"
}
echo "</div>";
}
?>
This query is running inside the foreach to fetch the comment for a particular post.
$comments = regular_query(
"SELECT a.from_who, a.dateposted, a.topostid, a.commenttext, b.firstn
FROM postcomments a
INNER JOIN users b ON a.from_who = b.id
WHERE a.topostid = :postid",
["postid" => $post_idr], $conn);
This one is outside the foreach:
$postinfo = regular_query(
"SELECT b.id, b.from_user, b.dateadded, b.posttype, b.posttext, b.photoname, d.firstn, d.lastn, e.status
FROM board b
INNER JOIN userprofiles c
INNER JOIN users d
INNER JOIN friendship e
ON b.from_user = c.user_id
AND b.from_user = d.id
AND e.friend_ids = b.from_user
WHERE e.status = 'Friend'
AND e.user_ids = :id
ORDER BY b.id DESC",
["id" => (int)$user_id], $conn);
Process One:
You can use one single query to get the one post and all its comment. But it has one problem For example One post have 20 comments so it will get post data 20 times
Query:
Select post.* form post join comment on post.postId=comment.postId where post.postId='your specific post id'
[You may have to change the query a lil bit or there may be some typo as i don't check it on tables]
Process Two:
Have two variable one is dic another is array
Post data will be in dictionary it will have one element with in it it will have comment array
$postData={
postId:1,
comment:({commentId:1,comment:"bla bla bla"},
{commentId:2,comment:"bla bla bla"}),
post:"bla bla post"
}
For post you have to run
Select * from post where postId=your specific id
And for comment
Select * from comment where postId=your specific id
As simple as that
Edit:
for(int i=0;i<postResult.count;i++)
{
if(i==0)
{
Print Your Post Info//so your post info will be echoed once
}
Print Your comment info//all your comment will be echoed here if any
}
Select postId,postTitle,postDesc,postedBy,postedAt,
commentId,commentTitle,commentDesc,commentedBy,commentedAt
from postTable JOIN commentTable ON postTable.postId = commentTable.postId
WHERE postTable.postId = 1 ORDER BY commentTable.postId DESC;
Iterate the Data like this :
{posts:[
{postId:1,postTitle:"title",postDesc:"desc",comments:[{comment1},{comment2}]},
{postId:2,postTitle:"title",postDesc:"desc",comments:[{comment1},{comment2}]}
{postId:3,postTitle:"title",postDesc:"desc",comments:[{comment1},{comment2}]}
]
}
Iterate the data using foreach
foreach($posts as $post){
foreach($comments as $comment){
}
}

Which JOIN to use

I'm trying to get info from a table.
I have boards and sub-boards. The column sub_id in table board tells me whether or not the board is a sub-board or not. If it is a sub-board then the id of the parent board is the value, if it isn't then the cell is null.
I wrote this to display whether or not a board has any sub-boards:
<?php
$data = mysql_query("SELECT * FROM board WHERE sub_id='$boardId'")
or die(mysql_error());
while($info = mysql_fetch_array( $data ))
{
Print "<br>Sub-collections:<br>";
Print "<font size='5pt'><a href='/board/index/".$info['id']."'>".$info['board_name']." </a></font>";
}
?>
This works fine.
Now I want to write a similar code to name the parent board (if the board is a sub) but this is where I'm having trouble.
I came up with:
<?php
$data = mysql_query("select * from board WHERE id='$boardId' AND sub_id IS NOT NULL") or die(mysql_error());
$issub = mysql_fetch_array($data);
?>
then using...
<?php if(($issub)): ?>
<?php echo $issub['sub_id'] ?>
<?php else: ?>
<?php endif ?>
To display.
The problem is without a join I cannot show anything other than the id of the parent board. I don't know which columns to join in order to extract info like board_name etc.
EDIT:
popovitsj's suggestion:
<?php
$data = mysql_query("SELECT * FROM board b WHERE EXISTS(SELECT * FROM board WHERE b.id = sub_id)") or die(mysql_error());
while($info = mysql_fetch_array( $data ))
{
Print "<br>Sub-collection of:<br>";
Print "<font size='5pt'><a href='/board/index/".$info['id']."'>".$info['board_name']." </a></font>";
}
?>
This works to a certain extent. It correctly displays the parent board on the subboard page, but also displays it erroneously on the parent board page.
EDIT2:
After researching LEFT JOIN at Meier's suggestion I eventually got it to work using this code:
SELECT * FROM board a LEFT JOIN board b ON a.sub_id = b.id WHERE a.sub_id LIKE b.id AND a.id='$boardId'
Before I answer the question: are you 100% sure that the $boardid does not come directly from http and is therefore manipulable by the user, so your users can not start a sql injection?
The join you need is a "outer self join". Outer join because you also want to display boards that do not have a parent. Outer join is also named left join.
A self join because the table is joined to itself. The trick with the self join is to give the table different names in the statement, so you can distinguish between th parent and the child.
A quick google search for "sql outer self join" gave me this, which explains it quite nicely.
The example is with employees and managers, and the managers are also employees. So the example is quite similar to yours:
http://blog.sqlauthority.com/2010/07/08/sql-server-the-self-join-inner-join-and-outer-join/
There are different solutions to this. One possible one is:
SELECT * FROM Board b
WHERE EXISTS
(SELECT * FROM Board
WHERE b.id = sub_id);
Another possible solution could be this, this only shows 'root' parent boards. (boards with no parents themselves).
SELECT * FROM Board b
WHERE sub_id IS NULL;

PHP: MYSQL COUNT query with linked tables

I am looking for a cleaner way to do this. My code works, but I know it can be better. I have three tables: one with a list of Category Groups, One with a list of categories that are linked to category groups, and one with a list of news stories that are linked to the categories.
I need to loop through all of the names of the Category Groups, followed by the names of the categories that are in the category groups, with the number of news stories in each category listed as well.
I have three tables: CategoryGroups, Categories, News.
I have a set of queries. The first queries all the rows from the CategoryGroups table:
$result = mysql_query( '
SELECT cat_group_id, cat_group_name FROM CategoryGroups
' );
The second query is inside the looped results of the first query and finds all the categories that have a news item and are linked to a specific category group:
<?php
while( $row = mysql_fetch_assoc( $result ) ){
$id = $row['cat_group_id'];
$name = $row['cat_group_name'];
echo "<h3>$name</h3>";
$sql = mysql_query("
SELECT category_id, title FROM `Categories`
WHERE cat_group_id = $id
AND category_id IN
(SELECT news.category_id FROM news)
");
while( $row = mysql_fetch_assoc($sql) ) {
$title = $row['title'];
$catid = $row['category_id'];
$numbers = mysql_query("
SELECT * FROM news
WHERE category_id =$catid"
);
$nums = mysql_num_rows($numbers);
echo "$title ($nums)<br/>\n";
}
?>
I would like to limit this to one or two queries, with efficiency in mind. I know this can be done, however I have not been successful in my attempts.
thanks.
Why not JOIN the tables?
SELECT cat_group_name, title, count(newsid)
FROM CatagoryGroups
INNER JOIN Categories ON cat_group_id
INNER JOIN News ON category_id
GROUP BY cat_group_name, title
looks like it should be close, if table news has a newsid column (it's gotta have SOME primary key, right? well, count that;-). With the obvious indexes the JOINs should be quite fast, and your PHP code can do whatever output formatting you may need from that.
I suggest you need to get a book on SQL, such as "SQL Queries for Mere Mortals."
$sql = mysql_query("
SELECT cg.cat_group_name, c.title, COUNT(n.category_id) AS NumNews
FROM `CategoryGroups` cg
JOIN `Categories` c USING (cat_group_id)
JOIN `News` n USING (category_id)
GROUP BY cg.cat_group_name, c.title");
Then loop over the result and output a new <h3> each time the cat_group_name is different from the previous row.

Categories