I am making a forum page using MySQL as database, but I'm coming from MongoDB and am a bit confused. When I fetch all posts for a specific category it looks something like this
SELECT p.id, p.posted_at, p.title, p.content, c.name AS category_name, u.name
AS author_name
FROM posts AS p
INNER JOIN users AS u ON p.author = u.id
INNER JOIN categories AS c ON p.category = c.id
WHERE p.category = 3 <-- Category ID
People can follow posts so I have a table called user_post_relations which contains two columns; user_id and post_id.
My goal is to add a follower count per post to the query that's getting all the posts per category. How can this be achieved with only one query?
Add the following JOIN with sub-query to your query
JOIN (SELECT post_id, COUNT(*) follower_count
FROM user_post_relations
GROUP BY post_id) AS upr ON upr.post_id = p.id
And then add upr.follower_count to your SELECT list
Related
How would I create a MySQL command to get the most recent categories that have had a post favorited?
I am attempting to join the tables and group them, but am unsure how to limit the results to a maximum number of categories.
So to give a simple example of what I'm trying to do:
Users (id)
Favorites (id, last_updated, post_id, user_id)
Posts (id, title, category_id)
Categories (id, name)
And then for sql:
SELECT favorites.*, posts.category_id
FROM favorites
INNER JOIN posts ON favorites.user_id = 1 AND favorites.post_id = posts.id
INNER JOIN categories ON posts.category_id = categories.id
GROUP BY categories.id, favorites.id
ORDER BY favorites.last_updated DESC
Obviously, this statement is not working as intended, as it returns many results for each category, instead of one for each category - the most recent.
You can't GROUP BY a field not present in SELECT.
Here is a solution assuming that you want this only for user_id = 1:
SELECT c.id, MAX(f.last_updated)
FROM favorites f
INNER JOIN posts p ON (f.user_id = 1 AND f.post_id = p.id)
INNER JOIN categories c ON (p.category_id = c.id)
GROUP BY c.id
ORDER BY MAX(f.last_updated) DESC
With this you get the IDs of the desired categories. You can join the result with categories again to get the rest of the columns.
I have categories with id, topics with id and category, and posts with id and topic. I'd like to list categories along with the number of topics belonging to each category as well as number of posts belonging to topics belonging to those categories.
what I'm using thus far to gather categories and their respective topic counts
select c.*, count(t.id) topics
from categories c
join topics t
on t.category=c.id
group by c.id
I've tried the following, but it just gives me the same post and topic count
select c.*, count(t.id) topics, count(p.id) posts
from categories c
join topics t
on t.category=c.id
join posts p
on p.topic=t.id
group by c.id
trying left join doesn't seem to make any difference
Use COUNT(DISTINCT t.id) to only count the unique topic ids per category.
select c.*, count(DISTINCT t.id) topics, count(p.id) posts
from categories c
join topics t
on t.category=c.id
join posts p
on p.topic=t.id
group by c.id
Alternatively, you can use subqueries:
select c.*,
count(t.id) topics,
( select count(p.id)
from posts p
where p.topic = t.id
) posts
from categories c
join topics t
on t.category=c.id
group by c.id
or even
select c.*,
( select count(t.id)
from topics t
where t.category = c.id) topics,
( select count(p.id)
from topics t
join posts p
on p.topic = t.id
where t.category = c.id) posts
from categories c
In this particular case count(distinct) is obviously the easiest, but in other cases, subqueries can give you more possibilities.
Basically I want to select all the posts that have at least one comment and get the comment count for each. What I cam up with so far is only giving me one result, which is has an accurate count but there are more than one posts that have comments. Can any recommend changes to make this work
SELECT
posts.id,
COUNT(DISTINCT comments.post_id) AS count
FROM
posts
LEFT JOIN comments ON posts.id = comments.post_id
Using aggregate functions you must group them see here GROUP BY (Aggregate) Functions for the posts must contain atleast one comment you can use HAVING count >= 1
SELECT
posts.id,
COUNT(DISTINCT comments.post_id) AS `count`
FROM
posts
LEFT JOIN comments ON posts.id = comments.post_id
GROUP BY posts.id
HAVING `count` >= 1
You need a group by statement. And you can change the join to an inner join because you want only posts with comments:
SELECT p.id, COUNT(*) AS count
FROM posts p INNER JOIN
comments c
ON p.id = c.post_id
GROUP BY p.id;
The expression count(distinct c.post_id) will return 1 for each row, because there is only one distinct post id for each row. COUNT(*) will get the number of comments.
Hi i'm struggling to write a particular MySQL Join Query.
I have a table containing product data, each product can belong to multiple categories. This m:m relationship is satisfied using a link table.
For this particular query I wish to retrieve all products belonging to a given category, but with each product record, I also want to return the other categories that product belongs to.
Ideally I would like to achieve this using an Inner Join on the categories table, rather than performing an additional query for each product record, which would be quite inefficient.
My simplifed schema is designed roughly as follows:
products table:
product_id, name, title, description, is_active, date_added, publish_date, etc....
categories table:
category_id, name, title, description, etc...
product_category table:
product_id, category_id
I have written the following query, which allows me to retrieve all the products belonging to the specified category_id. However, i'm really struggling to work out how to retrieve the other categories a product belongs to.
SELECT p.product_id, p.name, p.title, p.description
FROM prod_products AS p
LEFT JOIN prod_product_category AS pc
ON pc.product_id = p.product_id
WHERE pc.category_id = $category_id
AND UNIX_TIMESTAMP(p.publish_date) < UNIX_TIMESTAMP()
AND p.is_active = 1
ORDER BY p.name ASC
I'd be happy just retrieving the category id's releated to each returned product row, as I will have all category data stored in an object, and my application code can take care of the rest.
Many thanks,
Richard
SELECT p.product_id, p.name, p.title, p.description,
GROUP_CONCAT(otherc.category_id) AS other_categories
FROM prod_products AS p
JOIN prod_product_category AS pc
ON pc.product_id = p.product_id
LEFT JOIN prod_product_category AS otherc
ON otherc.product_id = p.product_id AND otherc.category_id != pc.category_id
WHERE pc.category_id = $category_id
AND UNIX_TIMESTAMP(p.publish_date) < UNIX_TIMESTAMP()
AND p.is_active = 1
GROUP BY p.product_id
ORDER BY p.name ASC
You would use an inner join to the product_category table, doing a left join there is pointless as you are using the value from it in the condition. Then you do a left join on the product_category table to get the other categories, and join in the categories for the data:
select
p.product_id, p.name, p.title, p.description,
c.category_id, c.name, c.title
from
prod_products p
inner join prod_product_category pc on pc.product_id = p.product_id
left join prod_product_category pc2 on pc2.product_id = p.product_id
left join prod_categories c on c.category_id = pc2.category_id
where
pc.category_id = #category_id and
unix_timestamp(p.publish_date) < unix_timestamp() and
p.is_active = 1
order by
p.name
I would really appreciate some help with my problem:
I have 2 MySQL tables, categories and posts, laid out (simplified) like so:
categories:
CATID - name - parent_id
posts:
PID - name - category
What I would like to do is get the total amount of posts for each category, including any posts in subcategories.
Right now I am getting the total number of posts in each (top-level) category (but not subcategories) by doing:
"SELECT c.*, COUNT(p.PID) as postCount
FROM categories AS c LEFT JOIN posts AS p
ON (c.CATID = p.category)
WHERE c.parent='0' GROUP BY c.CATID ORDER BY c.name ASC";
The question once again is, how can I get the sum totals for each category including the totals for each related subcategory?
Restructuring the database to a nested set format is not possible, as I am maintaining an existing system.
Thanks for your help!
If the categories are not nested infinitely, you can JOIN them one level at a time. Here's an example for up to 3 levels of nesting:
SELECT c.name, COUNT(DISTINCT p.PID) as postCount
FROM categories AS c
LEFT JOIN categories AS c2
ON c2.parent = c.catid
LEFT JOIN categories AS c3
ON c3.parent = c2.catid
LEFT JOIN posts AS p
ON c.CATID = p.category
OR c2.CATID = p.category
OR c3.CATID = p.category
WHERE c.parent = '0'
GROUP BY c.CATID, c.name
ORDER BY c.name ASC
I think you want to look at the Rollup operator. I believe this will get you what you want.
http://msdn.microsoft.com/en-us/library/ms189305(SQL.90).aspx
Randy