MySQL: How to get comment content and the post title - php

In Question and Answer system I am trying to get comment for question and answer and the title of that comment.
I have done so far and getting comment's content but now the issue is if the comment is on the answer it is not getting the question title. So how can I write query so it will get all comment from question and answer both and will get the title of the question.
Here I have done so far.
SELECT c.postid, p.title, c.type, c.userid, c.content, c.parentid, u.handle, u.email, u.avatarblobid, u.avatarwidth, u.avatarheight FROM qa_posts p
JOIN qa_posts c ON (p.postid = c.parentid)
LEFT JOIN qa_users u ON c.userid = u.userid
WHERE c.type = 'C'
AND p.flagcount = 0
ORDER BY c.postid DESC
LIMIT 5
Here is my table image and you can find type column is for Q, C and A question, comment and answer respectively.
Thanks a lot
EDIT:-------------------------------------------------------------
I have tried to check conditionally but this code also not working.. I hope you expert will guide to to correct this code
JOIN qa_posts AS parentposts
ON qa_posts.postid=(
CASE
LEFT(perentposts.type, 1)
WHEN
'A'
THEN
parentposts.parentid
ELSE
parentposts.postid
END
)
JOIN qa_posts AS cposts
ON parentposts.postid=cposts.parentid
LEFT JOIN qa_users AS cusers
ON cposts.userid=cusers.userid
JOIN (SELECT postid FROM qa_posts
WHERE type=$
ORDER BY qa_posts.created DESC
LIMIT 5)
y ON cposts.postid=y.postid
WHERE qa_posts.type='Q'
AND ((parentposts.type='Q') OR (parentposts.type='A'))

try this
SELECT * FROM qa_posts p
LEFT JOIN qa_users u ON c.userid = u.userid
WHERE p.type = 'C'
AND p.flagcount = 0
ORDER BY p.postid DESC
LIMIT 5

Related

Count user posts

I am listing the tags/categories on the user's page. I would like to show the number of posts the user made for each tag. The tags, the posts, and the post-tags are in different tables.
The difficulty is, that there are two kind of posts. The posts, and the comments. They are in the same table, but different type. "question" and "answer". the related_id at the answers are the id of the posts they are related to.
I tried to solve in pretty lot of way but couldn't get it to work.
My db structures:
For tags:
tagid tag_name
For posts
id type(enum:"question","answer") related_id user_id
For post-tags:
post_id tag_id
The code what I tried is the following:
$user_active_query = mysql_query("select p.id,
p.user_id,
pt.post_id,
count(pt.post_id),
pt.tag_id,
t.tagid,
t.tag_name
from posts p
inner join post_tags pt
inner join tags t
on p.id = pt.post_id
and pt.tag_id = t.tagid
where p.user_id = '$uid'
group by t.tagid");
while($useractive = mysql_fetch_array($user_active_query)) {
$user_active_counter = $useractive['count(pt.post_id)'];
echo "<a href='' class='btn btn-mini' style='margin:3px;'>".$useractive['tag_name']." (".$user_active_counter.")</a>";
}
User id is given on the page. "$uid". I am just tired of the lot of try and asking for correction. First it seemed to be the best way to store the post-tags but now this is a nightmare. I mean, for me, its seems impossible to do this with this structure.
You can get both counts i.e the no of answers and no of questions posted by a user ,here is the trick also use proper join syntax you are missing the on clause for join
SELECT
p.id,
p.user_id,
pt.post_id,
COUNT(pt.post_id) all_posts,
COALESCE(SUM(`type` = 'question')) questions,
COALESCE(SUM(`type` = 'answer')) answers,
pt.tag_id,
t.tagid,
t.tag_name
FROM tags t
LEFT JOIN post_tags pt ON(pt.tag_id = t.tagid)
LEFT JOIN posts p ON p.id = pt.post_id
WHERE p.user_id = '$uid'
GROUP BY t.tagid
Note in mysql sum with some expression will result in a boolean
Edit from comments add another condition using OR in your last join so first condition will join the posts that are associated with tags ,and as your explanation tags are not directly linked with answers but answer are linked to their question with related id so can join the related id of each answer to tag id so this way can get the tags for answers too
SELECT
p.id,
p.user_id,
pt.post_id,
COUNT(pt.post_id) all_posts,
COALESCE(SUM(`type` = 'question')) questions,
COALESCE(SUM(`type` = 'answer')) answers,
pt.tag_id,
t.tagid,
t.tag_name
FROM tags t
LEFT JOIN post_tags pt ON(pt.tag_id = t.tagid)
LEFT JOIN posts p ON (p.id = pt.post_id OR p.related_id = pt.post_id)
WHERE p.user_id = '$uid'
GROUP BY t.tagid
I think you only need to include p.type in your group by clause
$user_active_query = mysql_query("
select
p.id,
p.user_id,
pt.post_id,
count(pt.post_id),
pt.tag_id,
t.tagid,
t.tag_name
from posts p
inner join post_tags pt
inner join tags t
on p.id = pt.post_id
and pt.tag_id = t.tagid
where p.user_id = '$uid'
group by t.tagid, p.type"
);
so, we will group per type too.
I'm not sure I fully understand your schema design. But it sounds like you have two join "paths", one to get to the question type posts, and another to get to child answer type posts.
To get the count of the question-type posts (by a specific user) related to each tag, looks like what you have so far, basically:
SELECT t.tagid
, t.tag_name
, COUNT(p.id) AS count_question
FROM tags t
JOIN post_tags pt
ON pt.tag_id = t.tagid
JOIN posts p
ON p.id = pt.post_id
AND p.type = 'question'
WHERE p.user_id = '$uid'
GROUP BY t.tagid
To get the count of the answer-type posts (by a specific user) related to a question related to each tag, we first need to join to the 'question' (to get the tags), and then join to the related answer. This is nearly identical to the first query, except that we add another join to posts table to get the "child" answer-type posts (so we can get a count of the answer-type posts), and we are not restricting the question-type posts to those from the specific user... we are going to count the answer-type posts from a user posted against any user's question.
SELECT t.tagid
, t.tag_name
, COUNT(a.id) AS count_answer
FROM tags t
JOIN post_tags pt
ON pt.tag_id = t.tagid
JOIN posts p
ON p.id = pt.post_id
AND p.type = 'question'
JOIN posts a
ON a.related_id = p.id
AND a.type = 'answer'
WHERE a.user_id = '$uid'
GROUP BY t.tagid
If each of those queries returns a portion of the total count you want to return, those can be combined, but it gets a little bit messy.
The most straightforward approach is to combine those two results with a UNION ALL set operator, and then use that as an inline view, i.e. run another query against the combined resultset.
For example:
SELECT r.tagid
, r.tagname
, SUM(r.count_post) AS count_total
, SUM(IF(r.type='q',r.count_post,0)) AS count_question
, SUM(IF(r.type='a',r.count_post,0)) AS count_answer
FROM (
SELECT 'q' AS type
, t.tagid
, t.tag_name
, COUNT(p.id) AS count_post
FROM tags t
JOIN post_tags pt
ON pt.tag_id = t.tagid
JOIN posts p
ON p.id = pt.post_id
AND p.type = 'question'
WHERE p.user_id = '$uid'
GROUP BY t.tagid
UNION ALL
SELECT 'a' AS type
, t.tagid
, t.tag_name
, COUNT(a.id) AS count_post
FROM tags t
JOIN post_tags pt
ON pt.tag_id = t.tagid
JOIN posts p
ON p.id = pt.post_id
AND p.type = 'question'
JOIN posts a
ON a.related_id = p.id
AND a.type = 'answer'
WHERE a.user_id = '$uid'
GROUP BY t.tagid
) r
GROUP BY r.tag_id
If you aren't interested in the individual counts (of question and answer type posts), then just remove those two expressions from the SELECT list of the outer query, and you can also remove the type='q', type='a' discriminator column from the inline view query.
This isn't the only way to combine the results, but I think it's the easiest way to verify we're getting a "correct" result (we can run just the inline view query and verify that the results from that are correct.
Another approach to combining them is messier, and more difficult to decipher.
We basically need to join to question-type posts from all users, and then do an outer join operation to the answer-type posts from the specific user.
We can use predicates in the WHERE clause to filter out the rows, so that return only rows that have a matching answer-type row -OR- are a question-type row poseted by the specified user.
In the SELECT list, we need to do some additional filtering, so that we filter out posts from other users.
Something like this:
SELECT t.tagid
, t.tag_name
, COUNT(DISTINCT IF(p.user_id='$uid',p.id,NULL))
+ COUNT(DISTINCT a.id) AS count_total
, COUNT(DISTINCT IF(p.user_id='$uid',p.id,NULL)) AS count_question
, COUNT(DISTINCT a.id) AS count_question
FROM tags t
JOIN post_tags pt
ON pt.tag_id = t.tagid
JOIN posts p
ON p.id = pt.post_id
AND p.type = 'question'
LEFT
JOIN posts a
ON a.related_id = p.id
AND a.type = 'answer'
AND a.user_id = '$uid'
WHERE p.user_id = '$uid'
OR a.id IS NOT NULL
GROUP BY t.tagid
But, I'd don't really like this query, it's too hard to figure out what's going on. I'd opt for the (previous) query, with the UNION ALL inline view. That's easier to decipher.

how to order data in mysql by join count?

I have two tables :
posts : id,title,content,show,created_at
comments: id,post_id,created_at
I'm trying to order posts by most commented.
SELECT *, COUNT(comments.id) AS total_comments
FROM comments LEFT JOIN posts ON posts.id = comments.post_id
WHERE posts.show = '1'
GROUP BY complains.id
ORDER BY total_comments DESC
The problem is that the posts with 0 comments don't appear.
Any help would be much appreciated.
With your join above, you are incorrectly joining to get commens that have posts
You should have done a right join or swap the tables in left join like below.
Select *, COUNT(comments.id) as total_comments
FROM posts
LEFT outer JOIN comments on posts.id = comments.post_id
WHERE posts.show = '1'
GROUP BY posts.id
ORDER BY total_comments DESC
You need to do a RIGHT JOIN instead of a LEFT JOIN. Or swap the tables in the LEFT JOIN clause.
While there are many ways to solve this, I think this code is easy to read and understand.
The query in the LEFT JOIN can be copied out and run on its own to help debug. Then you join that result set to the posts table and order the results.
SELECT p.*, IFNULL(c.total_comments, 0) as total_comments
FROM posts p
LEFT JOIN (select post_id, count(post_id) as total_comments from comments group by post_id) as c ON p.id = c.post_id
WHERE p.show = '1'
ORDER BY c.total_comments DESC

MySQL joining tables with ORDER BY gives unexpected result

I have this database design:
**users_tbl**
id
username
name
**posts_tbl**
id
url
users_id *FK REFERENCE to users table*
**posts_contents_tbl**
id
posts_id *FK REFERENCE to posts table
title
description
date
views
click
isDeleted
I'm using this query
SELECT a.name,a.username,c.*
FROM users_tbl a
LEFT JOIN posts_tbl b ON a.id = b.users_id
LEFT JOIN posts_contents_tbl c ON b.id = c.posts_id
ORDER BY c.id ASC
Why I try to run this query it gives me NULL results, sample output is like this
But when I try to remove the ORDER BY c.id ASC it gives me this output:
That's not my expected result.
My expected result would be it will display the posts_contents_tbl in Ascending order at the same time it won't show some null values. Some users in my database doesn't have posts data in the posts_tbl so they should not show too.
How would I do that one? Your help would be greatly appreciated and rewarded!
Thanks!
PS: I already have thousands record in my database.
In that case, you have to use INNER JOIN instead of LEFT JOIN because you only want users with posts to show. The reason why there are Null values is because the records are based on table users_tbl and you've mentioned that some of them have no post. Right?
Try this:
SELECT a.name,
a.username,
c.*
FROM users_tbl a
INNER JOIN posts_tbl b
ON a.id = b.users_id
INNER JOIN posts_contents_tbl c
ON b.id = c.posts_id
ORDER BY c.`date` DESC
I think this is what you are looking for:
SELECT a.name,a.username,c.*
FROM users_tbl a
INNER JOIN posts_tbl b
ON a.id = b.users_id
LEFT JOIN posts_contents_tbl c
ON b.id = c.posts_id
ORDER BY IFNULL(c.id, 0) ASC;
If you really needs that posts_tbl data should not display if not available.And all data of posts_contents_tbl then you need a RIGHT JOIN and INNER JOIN .
The Query like :-
SELECT a.name,a.username,c.*
FROM users_tbl a
INNER JOIN posts_tbl b ON a.id = b.users_id
RIGHT JOIN posts_contents_tbl c ON b.id = c.posts_id
ORDER BY c.id ASC;

Why is this SQL giving a syntax error? [duplicate]

This question already has answers here:
Alternative to Intersect in MySQL
(9 answers)
Closed 8 years ago.
Trying to see what video categories "me_id" and "you_id" have both watched with:
SELECT c.title, COUNT(*) AS popularity
FROM video v
JOIN user u ON v.user_id = u.id
JOIN v_cat vc ON c.id = vc.vid_id
JOIN cat c ON c.id = vc.cat_id
JOIN u_cat uc ON uc.cat_id = c.id
WHERE uc.user_id = '$me_id'
INTSERSECT
SELECT c.title, COUNT(*) AS popularity
FROM video v
JOIN user u ON v.user_id = u.id
JOIN v_cat vc ON c.id = vc.vid_id
JOIN cat c ON c.id = vc.cat_id
JOIN u_cat uc ON uc.cat_id = c.id
WHERE uc.user_id = '$you_id'
GROUP BY c.title
ORDER BY uc.id DESC LIMIT 0, 10
I am working with PHP/MYSQL any thoughts?
MySQL doesn't have INTERSECT.
JOIN JOIN , Is that valid syntax?
FROM video v JOIN JOIN v_cat vc ON c.id = vc.vid_id
in the above line u have to use join one time..
I see two consecutive JOIN keywords in your first select but without any error message this is going to be difficult to debug.
Instead of INTERSECT, you can use the key word UNION or UNION ALL, this basically will do the intersection select. See http://dev.mysql.com/doc/refman/5.0/en/union.html

SQL- how to extract forum topics that are not repeats?

On the home page of my website I want to display the latest posts to the forum however I don't want to show the same topic twice. How can I modify the code below to do this?
http://punbb.informer.com/wiki/punbb13/integration#recent_10_posts
Basically show the latest posts, but only once for each forum topic/thread.
Add a condition to keep only records where the post is the last post in the topic:
WHERE p.id = (
SELECT pp.id
FROM posts AS pp
WHERE pp.topic_id = t.id ORDER BY pp.posted DESC LIMIT 1
)
If you want only one value per topic, you could group by topic, and from each topic select the most recent post. Then, you could choose the top 10 topics.
I'll write it in SQL, and you can translate that to PHP:
SELECT p.id, p.message, o.subject
FROM
((SELECT t.id
FROM posts AS p LEFT JOIN topics AS t ON p.topic_id = t.id
GROUP BY t.id
HAVING p.posted = MAX(p.posted) ) ids LEFT JOIN topics AS t ON ids.id = t.id) o
LEFT JOIN posts AS p ON o.id = posts.topic_id
ORDER BY p.posted DESC
LIMIT '0,10'
change this line
'SELECT' => 'p.id, p.message, t.subject',
to
'SELECT DISTINCT' => 'p.id, p.message, t.subject',

Categories