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.
Related
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;
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
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
I'm trying to display a list of items with their name and all categories they belong to.
My database structure is:
Items table with Id, Item_Name.
Categories table with Id, Category_Name
Items_Categories table with Id, Item_id, Category_id.
I'd like to display the results in a table with the Item Name, and a comma-delimited list of its Categories' Names. I'm not sure how to do this with a single query. Thanks in advance.
You need to use the GROUP_CONCAT function that is available in mysql:
select i.item_name, group_concat(c.category_name) as categories
from items i
inner join items_categories ic on i.id = ic.item_id
inner join categories c on ic.category_id = c.id
group by i.item_name
I won't write it for you, but you need to use group_concat() function (MySQL).
I must say I did not test this query, but it should be something similar to the following:
SELECT i.Id, i.Item_name, GROUP_CONCAT(c.Category_Name) AS category_list
FROM Items i
JOIN Items_categories ci ON ci.Item_id = i.Id
LEFT JOIN Categories c ON c.Id = ci.Id
GROUP BY i.Id
Note that you can use GROUP_CONCAT to create a comma seperated list.
SELECT i.Item_Name, GROUP_CONCAT(c.Category_Name) AS Category_List
FROM Items AS i
LEFT OUTER JOIN (
Items_Categories AS ic
INNER JOIN Categories AS c ON ic.Category_id = c.Id
) ON i.Id = ic.Item_id
GROUP BY i.Id;
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;