joining tables in mysql query? - mysql

I would like to run a query on two table "products" and "category", There are 30 record in my product table. product table has a column name category_ids varchar(255),which storing the ids of category in the format like(10,11,12,130,..) for each record of products table. In sort a product can be many categories. category table having a column name parent_id which is the parent category of that category.
I want to list the record with all category of that product.
For example look at one record of the products table having id = 7.
product_Id = 7,
category_ids = '213,215,216',
product_name = 'Ponds',
.....
Means product ponds has three category = category.id = 213, category.id = 215 and category.id = 216.
I want to list here all three records of ponds like in this format :=
product_Id | product_name | category_name | parent_category_name
7 ponds cream chemical
7 ponds medicine chemical
7 ponds powder Ayurvedic
I am trying with this query :-
select
p.id as product_id,
p.product_name,
child.name as category_name,
parent.name as parent_category_name
from category child
left join products p on child.id in(p.category_ids)
left join category parent on parent.id = child.parentid and parent.parentid = 0
where p.id = 7
The above query getting only one record not all three records as above.
What condition and joining in this query will be applied to get result as above described.
Sorry for spending your valuable time.
Any suggestions and ideas would be greatly appreciated.
Thanks a lot.

Try to change ON condition -
LEFT JOIN products p ON child.id IN(p.category_ids)
->
LEFT JOIN products p ON FIND_IN_SET(child.id, p.category_ids)
...because:
SELECT 1 IN ('1,2,3') find_1, 2 IN ('1,2,3') find_2;
+--------+--------+
| find_1 | find_2 |
+--------+--------+
| 1 | 0 | -- 0 !
+--------+--------+
SELECT FIND_IN_SET(1, '1,2,3') find_1, FIND_IN_SET(2, '1,2,3') find_2;
+--------+--------+
| find_1 | find_2 |
+--------+--------+
| 1 | 2 |
+--------+--------+
GROUP_CONCAT function.
example:
SELECT p.product_Id, p.product_name, GROUP_CONCAT(c.category) FROM products p
JOIN category c
ON FIND_IN_SET(child.id, p.product_Id)
GROUP BY p.product_Id;

Related

How to Count multiple records with specific type

I want to filter different records based on its category type
I have two table as
product and product_detail
product
p_id p_name p_cat_id
1 computer1 101
1 computer2 101
2 mobile1 102
2 mobile2 102
2 mobile3 102
product_detail
cat_id cat_name cat_staus
101 computer active
102 mobile active
103 electronics active
I want to count following records based on category type
such as computer1 and computer2 with cat_id so output will be computer = 2
query:
SELECT product_id,cat_name,
COUNT(DISTINCT product_detail.cat_name) AS "my_product"
FROM product
INNER JOIN product_detail ON product.p_id = product_detail.cat_id
GROUP BY product_detail.cat_id
If I understand correctly, you want to count the number of products that have a certain type of category; that is: "For each category, show the name of that category and the number of products with that category"
In that case, use this:
SELECT cat_name,
COUNT(1) AS amount
FROM product
INNER JOIN product_detail ON product.p_id = product_detail.cat_id
GROUP BY product_detail.cat_id
The INNER JOIN will already create a list of all products in a category. The GROUP BY will let you see each category specifically. All you need is the COUNT of rows for each category.
SELECT product.p_cat_id,
product_detail.cat_name,
COUNT(DISTINCT product.p_name) AS "my_product_count"
FROM product
LEFT JOIN product_detail
ON product.p_cat_id = product_detail.cat_id
GROUP BY product.p_cat_id
query:
SELECT product_detail.cat_name,
COUNT(p_cat_id) AS "my_product"
FROM product
INNER JOIN product_detail ON product.p_cat_id = product_detail.cat_id
GROUP BY product_detail.cat_name

Storing Item Relationships in MySQL

Background
I want to be able to store complex relationships between products in a MySQL database.
I currently have two tables. The first is a list of products:
ID | sku | division | retired
The second table is a relationship table
ID | prod1 | relation | prod2
With the idea being that prod2 has relation to prod.
Example Rows
Product Table:
1 | lamp | household | false
2 | lamp-short | household | false
3 | chair| household | false
4 | desk | household | false
5 | desk-realwood | household | false
6 | desk-extratall | household | false
6 | couch | household | false
Relations Table:
1 | 1 | child | 2 <- short lamp is child of lamp
2 | 4 | child | 5 <- real wood desk is child of desk
2 | 4 | child | 6 <- extra tall desk is child of desk
Then on a single product page for lamp, I'd like to have a "Related Products" box, so I need to pull in all related products. So I need an SQL query, that given the table names of products and product_relations and the ID of the current product, can pull in all rows in the products table that are related to the current product.
IE, if I'm looking at lamp, I need to pull in lamp-short.
I think I need to use a JOIN, but when I've tried it, I can't get it to work.
SELECT *
FROM `products`
INNER JOIN `product_relations` on products.id = ( product_relations.prod2 WHERE product_relations.prod1 = 1 )
5 being provided to the query.
Question
How would I write my query if I knew the ID of the current product, to get all related products?
If you wanted to get the related product sku and it's relationship to the original product searching by it's sku, you could use:
SELECT rp.sku, r.relation
FROM product p
INNER JOIN relations r ON p.id = r.prod1
INNER JOIN product rp on r.prod2 = rp.id
WHERE p.sku = '<original sku>'
This can be shortened, if you are searching by the original product's id, since then you don't really need the p aliased table above:
SELECT rp.sku, r.relation
FROM relations r
INNER JOIN product rp on r.prod2 = rp.id
WHERE r.prod1 = '<original product id>';
And you can add to that WHERE clause to filter by specific r.relation types, like 'Child' or what have you.
If they are children:
SELECT *
FROM products a
JOIN product_relations b
ON a.id = b.prod1
WHERE a.id = product_id_to_find
If you want all related:
SELECT *
FROM products a
JOIN product_relations b
ON a.id = b.prod1 OR a.id = b.prod2
WHERE a.id = product_id_to_find
These are entirely based on JNevill's answer. I'm adding them here and a more detailed reference for myself and others now that I understand how it works.
/***********************************************************************/
/******** GET ALL PRODUCTS "related" TO PRODUCT 1 (AND REVERSE) ********/
/***********************************************************************/
SELECT *
FROM products
JOIN product_relations
ON products.id = product_relations.prod2
WHERE product_relations.prod1 = 1 OR product_relations.prod2 = 1 AND product_relations.relation = "related"
/***********************************************************************/
/**************** GET THE CHILD PRODUCTS OF PRODUCT 1 ******************/
/***********************************************************************/
SELECT *
FROM products
JOIN product_relations
ON products.id = product_relations.prod2
WHERE product_relations.prod1 = 1 AND product_relations.relation = "child"
/***********************************************************************/
/**************** GET THE PARENT PRODUCT OF PRODUCT 1 ******************/
/***********************************************************************/
SELECT *
FROM products
JOIN product_relations
ON products.id = product_relations.prod1
WHERE product_relations.prod2 = 1 AND product_relations.relation = "child"
By flipping the lookup mechanics on the above, we don't have to have a child and a parent row in the product_relations table. The child row works for both.
/***********************************************************************/
/******** GET THE SUCCESSOR (NEW VERSION) PRODUCT OF PRODUCT 1 *********/
/***********************************************************************/
SELECT *
FROM products
JOIN product_relations
ON products.id = product_relations.prod2
WHERE product_relations.prod1 = 1 AND product_relations.relation = "successor"
/***********************************************************************/
/******* GET THE PREDECESSOR (OLD VERSION) PRODUCT OF PRODUCT 1 ********/
/***********************************************************************/
SELECT *
FROM products
JOIN product_relations
ON products.id = product_relations.prod2
WHERE product_relations.prod1 = 1 AND product_relations.relation = "predecessor"

SQL Multiple values in one column

I have two tables, the first is the products table, and it has 2 columns: id and product_name.
The second table is the filters table, and it has 2 columns: filter_id, product_id.
For example i have this in the products table:
id | product_name
1 | test product
and this in the filters table:
filter_id | product_id
1 | 1
2 | 1
3 | 1
As you can see, the product with id '1' has 3 filters.
My goal is to get the products by filters.
For example, i need every product where the product has the 2 and 3 filter_id. I tried to use something like that:
SELECT * FROM products p LEFT JOIN filters f ON (p.id = f.product_id) WHERE (filter_id = '2' AND filter_id = '3')
I can't do that because the filter_id can't be equal to 2 and 3 at the same time.
The main problem is that i should use only one query to get the products.
Group by the product and select only those having both filter_ids
SELECT p.id, p.product_name
FROM products p
JOIN filters f ON p.id = f.product_id
WHERE f.filter_id in (2,3)
group by p.id, p.product_name
having count(distinct f.filter_id) = 2

many to many to many mysql query

I'm trying to create a database that is structured so that I can do ONE query and get all the data I need.
this is how I have it structured now:
Products Subcategory Category
------------- ------------- -------------
| id | name | | id | name | | id | name |
It makes sense to me to create two relational tables that ties the product to the subcategory, and the subcategory to the category (making it hierarchical):
prod_sub_relation sub_cat_relation
---------------------------- ---------------------------
| id | prod_id | subcat_id | | id | subcat_id | cat_id |
So the product can be in MULTIPLE subcategories, and the subcategory tells us what category the product is in.
With this structure, if I wanted to find all the products with a category_id, I'd have to query the sub_cat_relation table, then take that array and make another query for the prod_sub_relation table (and that's just messy).
My goal is to find all products, or all categories, or all subcategories with ONE id (whether it's product_id, category_id, or subcategory_id)
Is this possible? or am I doing something wrong here?
As already mentioned by #har07 you could use a simple JOIN on this one.
I am not exactly sure the other details of the structure of your tables but
I will show you based on what you have provided so far:
SELECT p.ID, p.Name, c.Name as CategoryName, s.Name as SubCategoryName
FROM Products P
INNER JOIN SubCategory S
ON P.subcat_id = S.subcat_id
INNER JOIN Category C
ON S.cat_id = C.cat_id
You could then use a WHERE clause to specify which product you want to display along with its category and subcategory
SELECT P.ID, P.Name, C.Name as CategoryName, S.Name as SubCategoryName
FROM Products P
INNER JOIN SubCategory S
ON P.subcat_id = S.subcat_id
INNER JOIN Category C
ON S.cat_id = C.cat_id
WHERE P.ID = valuehereforyourID
To get the Products and SubCategory for a given category ID you just change the WHERE clause, like:
WHERE C.cat_id = ValueForCategoryIDhere
To get the Products and Category for a given Subcategory ID you just change the WHERE clause, like:
WHERE S.subcat_id = ValueForSubCategoryIDhere
Put each products' categories in an array, serialize the array, and store that in the DB...

Selecting against subsets of a list in MySQL

I'm quite a begginer and I have two tables: "product" and "product attributes".
Here's some imaginary data (the actual stuff involves more tables )
Products Table:
product_id | product_name
10 | aaa
11 | bbb
12 | ccc
Product Attributes Table:
attribute_id | product_id
21 | 10
23 | 10
24 | 10
21 | 11
24 | 11
21 | 12
25 | 12
Where each product has more than one possible attribute. I have a list of attribute ids like (21,10,25) and I need to select all products whose attributes are a subset of that list.
Is it possible to do this in one query?
When I filter for (21,24) desired output is to return only product 11 (bbb)
When I filter for (21,23,24) desired output is to return products 10 and 11.
When I filter for (21) desired output is to return none (because all products have at least one other attribute).
If you pretend that your filter is in a table:
select *
from product p
where not exists (
select 1
from attributes a
where a.product_id = p.product_id
and not exists(
select 1
from filter f
where f.id_attribute = a.id_attribute))
If it was in a constructed query:
select *
from product p
where not exists (
select 1
from attributes a
where a.product_id = p.product_id
and attribute_id not in (<list>))
This is off the top of my head, so may have typos.
Assuming your product table is called Product and the ID column in that table is just called Id:
SELECT * from Product p where p.Id IN
(Select id_product from ProductAttributes where id_attribute in (21, 23, 24))
This should return only those id's where all attributes for each id are completely contained within the list:
select attribute_match.id_product from
(select id_product, count(*) c from attributes
where id_attribute in (21, 10, 25)
group by id_product) attribute_match,
(select id_product, count(*) c_count from attributes
group by id_product) attribute_total
where attribute_match.id_product = attribute_total.id_product
and attribute_match.c = attribute_total.c
select
P.id,
P.name,
count(P.id) as matched_attr_count,
count(PA.a_id) as total_attr_count
from
product_attributes PA
left join product P on P.id = PA.p_id and PA.a_id in (21,23,24)
group by
PA.p_id
having
matched_attr_count = total_attr_count;
Until MySQL supports the EXCEPT query combination,
SELECT product_id
FROM attributes
WHERE product_id NOT IN (
SELECT product_id
FROM attributes
WHERE attribute_id NOT IN (21, 23, 24)
)
GROUP BY product_id
UNION
SELECT id
FROM products AS p
LEFT JOIN attributes AS a
ON p.id = a.product_id
WHERE a.product_id IS NULL
If you wish to have only the products with all the given attributes, add a HAVING COUNT(*)=n clause to the first outer query, where 'n' is the length of the attribute list.
Based on your insight guys, I optimized it even further and used only 1 COUNT statement like this:
SELECT * ,COUNT(p.product_id) AS c FROM product_attribute pa
LEFT JOIN products p ON pa.product_id = p.product_id AND pa.attribute_id NOT IN ($filter_list)
GROUP BY pa.product_id
HAVING c=0
Does it work ? :)
Edit:
That code doesn't return the product's name or other fields it might have. This is the correct one:
SELECT * ,COUNT(pa.product_id ) AS c FROM products p
LEFT JOIN product_attribute pa ON pa.product_id = p.product_id AND pa.attribute_id NOT IN ($filter)
GROUP BY p.product_id
HAVING c=0
let me post simple imaginary data ( the actual stuff involves more tables )
table products
product_id | product_name
10 | aaa
11 | bbb
table product_attribute
attribute_id | product_id <br>
21 | 10
23 | 10
24 | 10
21 | 11
24 | 11
i want that:
when I filter for (21,24) to be returned only product 11 (bbb)
when I filter for (21,23,24) to be returned both products
when I filter for (21) only to be returned none ( because no product has only that attribute )