1

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

3 Answers 3

5
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.

Sign up to request clarification or add additional context in comments.

3 Comments

I think using caps for the SQL parts makes queries considerably better to read. I allowed myself to edit it.
Uppercase keywords became useless and wasteful the second we got color screens and syntax high-lightning. I rolledback to my own personal taste.
I won't start a rollback war but I disagree with you. Quite often in the PHP world queries are placed between quotes and that will disable the coloring advantage.
2
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.

3 Comments

I think you put the tables in the wrong order (or you meant right join).
@Ronnis, I don't think so. I use queries like this and they work fine. As long as I want to get only the categories with some books assigned, this works ok.
Your query does not match your description of it. Categories with zero books will not be included in your result. To fix this, you either need to use RIGHT JOIN (if mysql supports it) or change the order of the tables. In fact, unless there are missing RI constraints and garbage data, your query is identical to an inner join.
1
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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.