SQL Multiple values in one column - mysql

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

Related

MySQL select records from related table

So I have two tables:
products
id
name
product_variants
id
product_id
name
barcode
I want to select all products with one query containing one field with the amount of related variants and one field with all related barcodes (seperated by space).
So for example this output:
product_id product_name product_variant_count product_variant_barcodes
1 Product 1 3 1234567890 0987654321 5432109876
2 Product 2 1 6789054321
3 Product 3 2 1234509876 3456781290
Is this possible?
As mentioned in the comments GROUP_CONCAT is perfect for this.
Selecting from products and joining onto product_variants:
SELECT p.id, p.name, COUNT(pr.id) AS product_variant_count,
GROUP_CONCAT(pr.barcode SEPARATOR ' ') AS product_variant_barcodes
FROM products p
LEFT JOIN product_variants pr ON (p.id = pr.product_id)
GROUP BY p.id

Matching items in one table that don't match in a subset of a second table

Suppose I have a Product table, and a
id product
1 Apple
2 Bag
3 Cat
4 Ducati
and a Cart table
id user_id product_id
1 1 2
2 1 3
3 2 1
4 3 1
So, I want to look at a particular user and see what he/she does NOT have in their Cart.
In other words, in the above example
SELECT ...... WHERE user_id=1 .....
would return Apple and Ducati because User 1 already has Bag and Cat.
(This may well duplicate another question but there are so many variations I couldn't find the exact match and put in these simple terms may help)
Perform a left join from product to all products purchased by user1, which can be retrieved with a subselect in the join. This will cause all product id's that are not in user1's care to have null product ids. The where clause will select all null product id's meaning they will not have been in a users cart, essentially filtering purchased items.
select p.name
from product p
left join (select product_id, user_id
from cart where user_id = 1)
c
on p.id = c.product_id
where c.product_id is null;
SQL Fiddle: http://sqlfiddle.com/#!2/5318eb/17
Select
*
From Product p
Where p.id Not In
(
Select c.product_id
From Cart c
Where User ID = ____
)
SELECT product FROM product_table
WHERE product NOT IN
(SELECT product_id FROM cart_table WHERE user_id = 1);
This will give you all product for all users which are not in there cart.
select c.user_id,a.Product
from cart c Cross Join product a
left Join
cart b on b.product_id=a.id and c.user_id=b.user_Id
where b.product_id is null
group by c.user_id,a.Product
Sql Fiddle Demo

joining tables in mysql query?

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;

How to select records who match criteria defined in a join table?

I have this three tables:
products TABLE:
id:integer
name:string
features TABLE:
id:integer
name:string
features_products TABLE:
product_id:integer
feature_id:integer
The features_products TABLE tells me which features have each product. For example:
product_id feature_id
1 3
1 5
3 4
tells me the product 1 has features 3 and 5 and product 3 have feature 4, also, product 2 (if exists) doesn't have features.
My question is, how can I SELECT all the products from the products TABLE wich have determinated features? For example, SELECT products which have features 3 AND 5, or SELECT products which have feature 2
To select all the product ids for products which have both features 3 and 5:
SELECT product_id
FROM features_products
WHERE feature_id IN (3, 5)
GROUP BY product_id
HAVING COUNT(*) = 2
This assumes that there is a uniqueness contraint on (product_id, feature_id). If you want the entire row from the product table then use this in a subquery:
SELECT *
FROM products
WHERE product_id IN (
SELECT product_id
FROM features_products
WHERE feature_id IN (3, 5)
GROUP BY product_id
HAVING COUNT(*) = 2
)
Something similar to this:
select * from product
where id in ( select product_id from feature_products where feature id in ( 1,3 ) )
swap out the (1,3) for the features you want to include.
You could do the following the join those tables and get the data you need:
SELECT *
FROM products p JOIN features_products fp ON p.id = fp.product_id
JOIN features f ON f.id = fp.feature_id
WHERE f.id = 3 OR f.id = 5

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 )