Display categories with number of posts - php

I'm making a blog. I have 2 tables, one for posts and the other for categories.
I want to display the category name, category date and the number of posts in each category. I have problems to display the number of posts in each category.
In posts table I have a column called cat_id which is equal to category.id
I have these 2 MySQL queries:
mysql_query("select Count(posts.id) as NumberOfPosts, cat_id from posts group by cat_id");
And
mysql_query("select name, date from categories");
I don't know how to have combine these two queries into one query. I'm using PHP.

You could use a join:
SELECT name, date, NumberOfPosts
FROM categories c
JOIN (SELECT cat_id, COUNT(*) AS NumberOfPosts
FROM posts
GROUP BY cat_id) p ON c.id = p.cat_id
EDIT:
To include categories with no posts, you could use a left join instead of regular join. You just need to handle the nulls you'd get for NumberOfPosts, e.g., by using coalesce:
SELECT name, date, COALESCE(NumberOfPosts, 0) AS NumberOfPosts
FROM categories c
LEFT JOIN (SELECT cat_id, COUNT(*) AS NumberOfPosts
FROM posts
GROUP BY cat_id) p ON c.id = p.cat_id

Related

join and group by not working properly in laravel

I have a blog with 2 table. First posts table with a key category_id and categories table. In a page I want to show all categories with count of their posts. I write this query but it have a problem. It did not show categories with no posts. in other word categories with 0 posts did not appear in the results.
And can you help to write this in eloquent system in laravel
SELECT categories.* , Count(posts.total) as total
FROM categories
LEFT JOIN
(
SELECT * , COUNT(*) as total from posts GROUP By posts.id
) as posts
ON posts.category_id = categories.id
Try following query:
SELECT categories.* , IFNULL(Count(posts.id),0) as total
FROM categories
LEFT JOIN
posts
ON posts.category_id = categories.id
Group by categories.id;

MySQL - WHERE / HAVING count

I searched lots of similar topics about this but can't find the answer to this specific probem.
So I have a table with categories and I have another table with products, so what I want is select all the categories that contain at least 1 product, seems very easy but the following code dont give me what I expect.
SELECT *
FROM categories
INNER JOIN products on (categories.id = products.cat_id)
HAVING count(products.cat_id) > 0
All help is appreciated.
Thank you!
You can actually get what you want with just a join because any categories without products will not match.
You should also add a DISTINCT or GROUP BY to remove the duplicate category records from the results:
SELECT DISTINCT c.*
FROM categories c
JOIN products p
ON c.id = p.cat_id
OR:
SELECT c.*
FROM categories c
JOIN products p
ON c.id = p.cat_id
GROUP BY c.id
If you want something fancy like categories that have 2 or more products then you can use GROUP BY and HAVING:
SELECT c.*
FROM categories c
JOIN products p
ON c.id = p.cat_id
GROUP BY c.id
HAVING count(*) >= 2
Try this select in this select all categories that have at least one product
select categories.* from categories
left join products on (categories.id = products.cat_id)
where products.cat_id IS NOT NULL
group by categories.id
In this case you're not using "HAVING" but will have the same result

Displaying categories without repeating each that has posts

I have categories table:
cat_id
cat_name
Than categories - posts relationship table cat_rel:
cat_rel_id
cat_id
post_id
And posts table:
post_id
post_title
post_content
Now I have data in all these tables, I need to pull out categories without to repeat those that have more than 1 post. I get somehow category repeated if it has more than 1 post, eg. categories like:
php, python, c++, java, ruby
if I have 2 posts under PHP, I will get:
php
python
php
java
and this is the query I run:
SELECT categories.cat_name, cat_rel.post_id
FROM categories
LEFT JOIN cat_rel ON cat_rel.cat_ID = categories.cat_ID
Any help about making those categories not to repeat, would be appreciated
Use DISTINCT
Have a look here:
SQL SELECT DISTINCT Statement
This would list the categories with more than one post:
SELECT categories.cat_name as Category
, count(distinct cat_rel.post_id) as PostCount
FROM categories
LEFT JOIN cat_rel
ON cat_rel.cat_ID = categories.cat_ID
GROUP BY categories.cat_name
HAVING count(distinct cat_rel.post_id) > 1
Try this:
SELECT DISTINCT categories.cat_name, cat_rel.post_id
FROM categories
LEFT JOIN cat_rel ON cat_rel.cat_ID = categories.cat_ID

Getting multiple counts from two joined tables in MySQL

So I have two tables, categories and designs. I want to construct a query that will fetch all categories, along with the count of any sub categories (categories.parent_id equal to the categories.id) AND the count of any designs (design.category_id equal to categories.id)
If I try to just get one of these counts, everything works fine, but when I try for both with the following code, the count for both is the same number (and not the correct number) for either.
$this->db->select('categories.id AS id, categories.parent_id AS parent_id, categories.title AS title,
categories.description AS description, categories.img_path AS img_path, COUNT(designs.id) AS design_count,
COUNT(sub_categories.id) as sub_category_count');
$this->db->from('categories');
$this->db->join('designs', 'categories.id = designs.category_id', 'left');
$this->db->join('categories as sub_categories', 'categories.id = sub_categories.parent_id', 'left');
$this->db->group_by('categories.id');
Any help will be much appreciated, cheers!
Assuming that the root categories do not contain designs, here is the query that returns the necessary information:
SELECT category.id, category.title, subcategory.id, designs.id
FROM categories category
LEFT JOIN categories subcategory ON category.id = subcategory.parent_id
LEFT JOIN designs ON subcategory.id = designs.category_id
WHERE category.parent_id IS NULL
Now all you need to do is to apply grouping:
SELECT category.id, category.title, COUNT(DISTINCT subcategory.id), COUNT(designs.id)
FROM categories category
LEFT JOIN categories subcategory ON category.id = subcategory.parent_id
LEFT JOIN designs ON subcategory.id = designs.category_id
WHERE category.parent_id IS NULL
GROUP BY category.id, category.title
The key here is the use of COUNT(DISTINCT ...).
SELECT c.id,c.title,
IFNULL(sc.counted,0) AS subcategories,
IFNULL(d.counted,0) AS designs
FROM categories c
LEFT JOIN
( SELECT parent_id,COUNT(*) AS counted
FROM categories GROUP BY parent_id ) sc
ON c.id=sc.parent_id
LEFT JOIN
( SELECT category_id,COUNT(*) AS counted
FROM designs GROUP BY category_id ) d
ON c.id=d.category_id
WHERE c.parent_id IS NULL ;
should get you the desired numbers as raw SQL.

Help with a MySQL query

Given the following tables I would like to know how to write a query to return only the categories that have books in them and the number of books for each category. A book can be added in one or many categories. I'm using PHP and MySQL.
Here are my tables:
categories table
- id
- name
- permalink
books table
- id
- title
- author
- description
- price
books_categories table
- id
- book_id
- category_id
select c.id
,c.name
,count(*) as num_books
from categories c
join books_categories bc on(bc.category_id = c.id)
group
by c.id
,c.name;
Use LEFT JOIN if you also want the categories without books.
SELECT *, COUNT(*) AS count
FROM books_categories AS bc
LEFT JOIN categories AS c ON c.id = bc.category_id
GROUP BY c.id
You'll get a count column with the number of rows for each category. Categories with zero books (that is those with no entry in table books_categories) won't be returned.
SELECT categories.id,
COUNT(books_categories.id) AS number
FROM categories
LEFT JOIN books_categories ON books_categories.category_id = categories.id
GROUP BY categories.id
HAVING number > 0;

Categories