Display Parent Count base on the grand-child - mysql

i have two tables
Table1 : Categories ,
Columns : id , parent_id , name
Table2 : products ,
Columns : id , product_name , category_id , subcategory_id , sale_wanted
Here is the detail
A category can have multiple subcategories id. Parent id 0 means it s a category and parent id != 0 means it is a subcategory. Now each product is related to a subcategory. I need to display the names of category and total subcategories count related to each category.
sale 0 means the product is for sale and 1 means it is required.
Now i need this.
1.Display all categories and count of subcategories related to each category where the products related to category are for sale.

The problem it is that your structure is recursive.
I think you can search for more informations about intervallic representation.

Well i have found this solution
select
dc.category_id,
dc.name ,
count(ldc.name) as total
from default_category as dc
inner join default_category as ldc on ldc.parent_id= dc.category_id
inner join(select * from default_products where sale_wanted = 1) as dp on dp.subcategory_id = ldc.category_id
where dc.parent_id = 0
group by dc.category_id
This works well.

Related

SQL LEFT JOIN with two tables - table order and performance

I got an LEFT JOIN exercise at school:
"List all category names with the number of their products."
Used were two tables from the northwind DB: products (77 rows) and categories (8 rows)
I thought the product table should come first, since the main-data (number of products) will be found there and only the 8 category names will be needed from the joined table. Our teacher argued, that the categories table needs to be the main table, but i still can't understand why.
The two queries are:
SELECT C.CategoryID, CategoryName, COUNT(ProductID) [Count]
FROM Categories C LEFT JOIN Products P
ON C.CategoryID = P.CategoryID
GROUP BY C.CategoryID, CategoryName
and
SELECT P.CategoryID, CategoryName, COUNT(ProductID) [Count]
FROM Products P LEFT JOIN Categories C
ON P.CategoryID = C.CategoryID
GROUP BY CategoryName, P.CategoryID
Can anybody explain to me why, in this case, a certain order of used tables matters in terms of theoretical performance?And if: how so? (does size matter?;))
The name of the exercise tells yo what is the first table in your case.
"List all category names with the number of their products."
So get the all category names. Category names is what you HAVE TO SHOW - ALL OF THEM. You want to show all of them regardless of the fact is there a matching CategoryID in the Products table.
For example, if you want to show all product names with number of their categories then you want to show all product names regardless if there exists matching ProductID in Categories table.
Here is the demo
This demo shows you what the two queries will return if we have 3 categories and one product. It is not the best demo in the world but it does the trick I believe.
The tables:
create table Categories (CategoryID int, CategoryName varchar(20))
create table Products (ProductID int, CategoryID int)
The data:
insert into Categories values(1, 'Cat1');
insert into Categories values(2, 'Cat2');
insert into Categories values(3, 'Cat3');
insert into Products values(1, 1);
Query1:
SELECT C.CategoryID, CategoryName, COUNT(ProductID) as Cnt
FROM Categories C
LEFT JOIN Products P ON C.CategoryID = P.CategoryID
GROUP BY C.CategoryID, CategoryName
Result1:
CategoryID CategoryName Cnt
1 Cat1 1
2 Cat2 0
3 Cat3 0
Query2:
SELECT P.CategoryID, CategoryName, COUNT(ProductID) as Cnt
FROM Products P
LEFT JOIN Categories C ON P.CategoryID = C.CategoryID
GROUP BY CategoryName, P.CategoryID
Result2:
CategoryID CategoryName Cnt
1 Cat1 1
I see in your question that you say:
"Used were two tables from the northwind DB: products (77 rows) and categories (8 rows)"
So maybe it is strange now for you how can my example be like this and yours "since the results of both queries are obviousely the same" ?
Here is the demo that will show you how it can be the same with different set of data.
As an aside, here is another way to get the desired results.
SELECT C.CategoryID, C.CategoryName
( SELECT COUNT(*)
FROM Products AS P
WHERE P.CategoryID = c.CategoryID
) AS "Count"
FROM Categories AS C
The performance will be about the same as the 'correct' LEFT JOIN formulation.
A further note: COUNT(x) does the extra check to see that x IS NOT NULL; COUNT(*) simply counts the number of relevant rows.
In some other situation, you may need COUNT(DISTINCT productID); I suspect you do not need it in this case.

SQL query for a selection from a table with categories and subcategories

Structure of the Category table:
id
title
parent_id
Structure of the Item table:
id
title
is_active (0 или 1)
category_id
table structure
Tables are associated with the category_id field by a one-to-many relationship. Those. 1 category can have many items.
The two-level hierarchy in the Category table. This defines the main categories and subcategories. Categories are those records in which parent_id = NULL. And subcategories, these are those records in which parent_id = to some id.
One Item can belong to both the main category (where parent_id = null) and the subcategory (child). Item can be active and not active (0 or 1).
You need to make a query and select from the Category table all the main categories (which have parent_id = null) that have active items (is_active = 1) and which have subcategories also with active itemes.
i.e If the child subcategory has items with is_active = 0, then do not display this category.
I could only choose the main categories in which only active items:
SELECT categories.title, count(analyses.id) FROM items
INNER JOIN categories on items.category_id = categories.id
WHERE categories.parent_id IS NULL
AND categories.is_active = 1
GROUP BY analyses.category_id
ORDER BY analyses_categories.title
But with subcategories can not cope anymore, tell me please who has more experience.
It's a little unclear what you are trying to count (just the active items associated with the parent?), but I would use exists to find out which have children with active items as well:
select c.title, count(*)
from categories c
join item i on i.category_id = c.id
where c.parent_id is null and i.is_active = 1 and exists (
select 1
from categories c2
join item i on c2.id = i.category_id
where c2.parent_id = c.id and i.is_active = 1
)
group by c.title

how i do this sql trick

I have a table in database for categories and sub categories. Its internal structure is:
id int not null primary
name text
subcatfrom int
it contains some of rows for categories and its sub categories. I want "SELECT" sql command to fetch categories and grouping their sub categories after it for every root category as following for example :
-cat1
--subcat1
--subcat2
-cat2
--subcat1
--subcat2
is it possible ?
The original question wants the subcategories on separate rows. Here is one way:
select name
from ((select category as name, 1 as iscat, category as sortorder
from t
) union all
(select tsub.category as name 0 as iscat, t.category as sortorder
from t join
tsub on
on t.subcategory_id = s.category_id
)
) a
where not exists (select 1 from category c where c.subcategory_id = a.sortorder limit 1)
order by sortorder, iscat desc, name
What is this doing? The inner union all is bringing together all categories and subcategories. It is assigning what you want in the table as well as information for sorting. The overall ordering is by "parent" category name.
The where clause is limiting this data to categories that are not the subcategory of anything else -- the top level categories.
I am making the assumptions that-
1. you have just one level of parent child relationship. ie subcategory can't have further sub-category
2. For top level category, value of subcatfrom is 0
SELECT * FROM
(
SELECT NAME AS parent_category_name, '' AS child_category_name FROM categories WHERE subcatfrom = 0
UNION
SELECT b.NAME AS parent_category_name, a.NAME AS child_category_name FROM categories a JOIN categories b ON a.subcatfrom = b.id
) a ORDER BY a.parent_category_name, a.child_category_name;
That's very easy but with this structure
Table: category_id , name , parent_id
Sample Data
category_id name parent_id
1 A 0
2 B 0
3 C 1
4 D 1
This means A is a category which has 2 subcategories C and D. And parent_id 0 means it is a parent category
Now the sql is
SELECT lc.category_id,
lc.name,
rc.subcategories
FROM categories
LEFT JOIN (
SELECT
subcategory_id ,
GROUP_CONCAT(name) AS subcategories
FROM categories) AS rc
ON lc.category_id = rc.parent_id
This will give you the following result
category_id name subcategories
1 A C,D
2 B (null)

Retrieve parent category name from table in MYSQL results

I have a MYSQL table called 'categories' from a project I inherited from someone else.
id parent_id name
1 NULL Travel
2 NULL Sleep
3 NULL Eat
4 NULL Bath
5 1 Prams
6 1 Travel Systems
7 2 Cots
8 3 High Chairs
The table is obviously a lot bigger than that, but you get the general idea. I have a MYSQL statement which brings together this table with other category, brand and product tables, but basically I want to list the parent category name from the above table with the sub-category in the statement. How do I do this?
My current statement is something like:
SELECT brands.name, products.name, categories.id, categories.name, brands.id,
FROM `products` , `brands` , `categories`
WHERE products.brand_id = brands.id
AND products.category_id = categories.id
AND brands.name = '$brand'
ORDER BY categories.name, products.name
How do I retrieve the parent category names in the results?
For example if the product is a Pram, how can I output "Travel". I could do seperate MYSQL statements in the loop but I want to avoid this. This is either a stupidly simple question (in which case I apologise for being brain dead) or a little more complicated! Thanks.
First you need to know the parent id of the current category and then get the name for that id, you could use a subquery in this way:
SELECT name FROM categories WHERE id = (SELECT pid FROM categories WHERE name = $brand)
EDIT: Since you need to get the category and subcategory names in the same row for a given subcategory id, try this:
SELECT sc.name AS subcategory, c.name AS category
FROM categories sc
LEFT JOIN categories c ON c.id = sc.parent
WHERE sc.id = $subcategory_id

MySQL nested set hierarchy with foreign table

I'm using a nested set in a MySQL table to describe a hierarchy of categories, and an additional table describing products.
Category table;
id
name
left
right
Products table;
id
categoryId
name
How can I retrieve the full path, containing all parent categories, of a product? I.e.:
RootCategory > SubCategory 1 > SubCategory 2 > ... > SubCategory n > Product
Say for example that I want to list all products from SubCategory1 and it's sub categories, and with each given Product I want the full tree path to that product - is this possible?
This is as far as I've got - but the structure is not quite right...
select
parent.`name` as name,
parent.`id` as id,
group_concat(parent.`name` separator '/') as path
from
categories as node,
categories as parent,
(select
inode.`id` as id,
inode.`name` as name
from
categories as inode,
categories as iparent
where
inode.`lft` between iparent.`lft` and iparent.`rgt`
and
iparent.`id`=4 /* The category from which to list products */
order by
inode.`lft`) as sub
where
node.`lft` between parent.`lft` and parent.`rgt`
and
node.`id`=sub.`id`
group by
sub.`id`
order by
node.`lft`
To fetch parents nodes you need only... left/right values of last (SubCategory n) node.
Fetch your product: SELECT ... FROM product p JOIN category c ON c.id = p.category_id WHERE p.id = ?.
Fetch parents: SELECT ... FROM category WHERE leftCol <= {productCategory['left']} AND rightCol >= {productCategory['right']}
That's pretty everthing you need.
Hey, I think I solved it! :D
select
sub.`name` as product,
group_concat(parent.`name` separator ' > ') as name
from
categories as parent,
categories as node,
(select
p.`name` as name,
p.`categoryId` as category
from
categories as node,
categories as parent,
products as p
where
parent.`id`=4 /* The category from which to list products */
and
node.`lft` between parent.`lft` and parent.`rgt`
and
p.`categoryId`=node.`id`) as sub
where
node.`lft` between parent.`lft` and parent.`rgt`
and
node.`id`=sub.`category`
group by
sub.`category`