I have three tables, Users, Articles and Comments, as below:
Users:
id | username
Articles:
id | user_id | title | content | time
Comments:
id | article_id | content | time
user_id is the article writer's user id in Users; article_id is the commenting article's id in Articles.
Now I want to list articles, showing their writer's username, title, content, time, and number of comments. The username is from Users, number of comments should be from Comments by counting something, and the rest fields are from Articles.
How to write the query in a single statement?
I tried
SELECT a.*, count(c.id) AS NUM_COMMENTS, u.username
FROM Commetns c
JOIN Users u
INNER JOIN Articles a
WHERE a.id = c.article_id AND u.id=a.user_id
GROUP BY a.id
But this only returns articles with comments. I want the articles without comments also listed.
You need left join to get the articles without comments
select
a.*,
count(c.id) AS NUM_COMMENTS,
u.username
from Articles a
JOIN Users u on u.id=a.user_id
left join Commetns c on c.article_id = a.id
GROUP BY a.id
Related
I have three tables and Im trying to count the number of likes per user on all his/her post.
USER TABLE
id name
1 John
2 Joe
POSTS TABLE
id user_id post_title
1 1 Some Title
2 1 Another Title
3 2 Yeah Title
LIKES TABLE
id post_id
1 1
2 1
3 1
4 2
5 3
My expected output is
ID LIKES
1 4
2 1
Im kinda stuck with the code below. I don't know how to add and count the likes table.
SELECT *
FROM user
INNER JOIN posts
ON user.id = posts.user_id;
You need to extend the join to the LIKES table and then use GROUP BY to group by the user ID and COUNT() all of the records for that user...
SELECT user.id, COUNT(likes.id)
FROM user
INNER JOIN posts ON user.id = posts.user_id
INNER JOIN likes ON posts.id = likes.post_id
GROUP BY user.id
If you want to list people who don't have posts or likes, then you should use outer joins (so change INNER JOIN to LEFT JOIN) so that these users show up.
For your desired result, you don't need the user table. You can simply do:
SELECT p.user_id, COUNT(*)
FROM posts p JOIN
likes l
ON l.post_id = p.id
GROUP BY p.user_id;
The only information you are taking from users is the id, which is already in posts. This assumes that all the user_id values in posts are valid, but that seems like a very reasonable assumption.
I have simple magazine, and have tables with posts, comments, categories, etc. When listing single category, I want to have sum of comments per post in a listing, but that number is just wrong and it is driving me crazy. Note that single post can be in multiple categories.
Here are the simple tables structures
posts
id | title | categoryid | content | published
---------------------------------------------
comments
id | postid | comment
---------------------
category_rel
postid | categoryid
-------------------
categories
id | category
-------------
I use following sql (simplified to this example):
SELECT posts.*, categories.id AS categoryid,
categories.category AS categorytitle,
COUNT(comments.postid) AS CNT
FROM posts
LEFT JOIN comments ON posts.id = comments.postid
INNER JOIN category_rel ON posts.id = category_rel.postid
INNER JOIN categories ON category_rel.categoryid = categories.id
WHERE posts.published=1
GROUP BY posts.id;
This statement is giving me wrong results, sometning like it's cumulating number of categories post is member of and multiplying with actual number of comments. If I remove category part of SQL (which is not good, I need category Id and name) I receive proper values:
SELECT posts.*, COUNT(comments.postid) AS CNT
FROM posts
LEFT JOIN comments ON posts.id = comments.postid
WHERE posts.published=1
GROUP BY posts.id;
To be more specific:
One of posts have 1 comment and it is member of 7 categories. value CNT is going to 7, not 1.
Any idea how to change first SQL to get proper values?
You want to count the comments per post - not per category. So one way of achieving this would be to do the count first (in a subselect as MySQL has no CTE so far) and then join the results into category table:
SELECT countpost.*, categories.id AS categoryid,
categories.category AS categorytitle
FROM
-- subselect post and comment count
(
SELECT posts.*, count(comments.postid) as CNT FROM posts
LEFT JOIN comments ON posts.id = comments.postid
WHERE posts.published = 1
GROUP BY posts.id
) as countpost
-- join category table
INNER JOIN category_rel ON countpost.id = category_rel.postid
INNER JOIN categories ON category_rel.categoryid = categories.id ;
See this fiddle: http://sqlfiddle.com/#!9/f9c6f/1
I am have four tables in my DB for a simple forum that I am coding.
Topics:
topic_ID | name | description
Threads:
thread_ID | topic_ID | name | description
Messages:
message_ID | thread_ID | title | message | date | user_ID
Users:
user_ID | name | email | username
I want to run one query to do the following:
Display the available topics, the number of threads associated with each topic, the number of messages associated with each topic, the date latest message posted and the user who posted it.
So one row of the result would say something like:
Topic: Admin
Threads: 4
Posts: 50
Newest message: 2016/05/18 by pixelled
I started with this (which worked):
SELECT topics.topic_id, topics.name, count(threads.topic_id) AS 'totals'
FROM topics
LEFT JOIN threads
ON topics.topic_id = threads.topic_id
GROUP BY threads.topic_id
I then added the messages table:
SELECT topics.topic_id, topics.name, count(threads.topic_id) AS 'totals', MAX(messages.date) AS 'Newest'
FROM topics
LEFT JOIN threads
ON topics.topic_id = threads.topic_id
LEFT JOIN messages
ON messages.thread_id = threads.thread_id
GROUP BY threads.topic_id
But the results of this query show the wrong values for the totals column.
Adding the users table works:
SELECT topics.topic_id, topics.name, count(threads.topic_id) AS 'totals', MAX(messages.date) AS 'Newest', users.username
FROM topics
LEFT JOIN threads
ON topics.topic_id = threads.topic_id
LEFT JOIN messages
ON messages.thread_id = threads.thread_id
LEFT JOIN users
ON users.user_ID = messages.user_ID
GROUP BY threads.topic_id
Please help me to complete this query so that the correct value shows in the totals column.
Here is the fiddle:
http://sqlfiddle.com/#!9/0f926
Try
count (distinct threads.thread_id)
This was the query that gave the correct results:
SELECT topics.topic_id, topics.name, topics.description, count(threads.topic_id) AS 'totals', MAX(m.date) AS 'Newest', users.username
FROM topics
LEFT JOIN threads
ON topics.topic_id = threads.topic_id
LEFT JOIN
(
SELECT thread_id, date, user_id
FROM messages
GROUP BY thread_id
) m
ON m.thread_id = threads.thread_id
LEFT JOIN users
ON users.id = m.user_id
GROUP BY threads.topic_id
It was duplicating the threads table because it was joined twice.
I have two tables, Article and Comments.
Now I want to know the number of articles which have less than 5 comments.
How can I do that?
Articles:
id | author_id | title | cotent
Comments:
id | article_id | author_id | content
Edit: the original question is about larger than, but now I actually want less than (e.g., <5). If there is no comment record for an article, it seems this article is not listed.
Join both table to get the comments of articles and then group it by article id to know comment count of each article.
Try out this:
select art.id,count(*) as comment_count
from articles art
inner join comments com on art.id=com.article_id
group by art.id
having comment_count>5
For articles having comments <= 5:
select art.id,count(*) as comment_count
from articles art
left join comments com on art.id=com.article_id
group by art.id
having comment_count<=5
Try this
SELECT a.id, COUNT(*)
FROM
articles a
LEFT OUTER JOIN comments c ON a.id=c.article_id
GROUP BY a.id
HAVING COUNT(*) > 5
this will return id of all articles having more than 5 comments, with their respective comment count
I have a table - comments. Users can post if not a member of the site but want to show their details if they are.
So if a user comments who is NOT a member I show their posts but don't link to their profile, because they don't have one.
So, in the following query I want to return the rows even if there is no join:
select wc.comment, wc.comment_by_name, wc.user_id, u.url from comments wc
join users u on wc.wag_uid = u.user_id
where id = '1237' group by wc.comment order by wc.dateadded desc
I want to return:
comment comment_by_name user_id url
------- --------------- ------- ----
hello dan 12 /dan
hey jane /jane
world jack 10 /jack
But the above does not return the data for jane as she does not have a user_id
Is there a way to return all data even if the join is null?
use LEFT JOIN instead
SELECT wc.comment, wc.comment_by_name, wc.user_id, u.url
FROM comments wc
LEFT JOIN users u
on wc.wag_uid = u.user_id
WHERE id = '1237'
GROUP BY wc.comment
ORDER BY wc.dateadded DESC
basically INNER JOIN only select records which a record from one table has atleast one match on the other table while LEFT JOIN select all rows from the left hand side table (in your case, it's comments) whether it has no match on the other table.