Reputation: 327
I have inherited a DB that has products, where each product has attributes, which are organised in groups ,
I need to construct a query that allows a user to specify a bunch of attributes and return the products that have at least one match in each group.
So if a product has a color of blue, size: xl and collarshape is vneck, and a user chooses blue, green, vneck xl xxl, then the above product would match. If the product only had the color yellow it would not match
Below is the table structure..
E.g. colors : blue, yellow, green, sizes: xl xxl l s, collarshape: vneck, crewneck
\ the products,
CREATE TABLE products (
id integer,
name varchar(40),
PRIMARY KEY(id)
);
// join attributes and products
CREATE TABLE attributes_products (
product_id integer,
attibute_id integer
);
// attributes // e.g blue, yellow, green , xl, xxl, l, s ,vneck, crewneck
CREATE TABLE attributes (
id integer,
label varchar(40),
attribute_group_id integer
);
// e.g collarshape , color , size
CREATE TABLE attribute_group (
id integer,
label varchar(40)
);
Upvotes: 0
Views: 75
Reputation: 4615
I think this query will give the desired output
SELECT * FROM products WHERE id IN (
SELECT product_id
FROM attributes_products
GROUP BY product_id
HAVING (array_agg(attibute_id) @> ARRAY[90,93])
)
SELECT * FROM products
INNER JOIN (
SELECT product_id
FROM attributes_products
GROUP BY product_id
HAVING (array_agg(attibute_id) @> ARRAY[90,93])
) AS availableproduts ON products.id = availableproduts.product_id
SELECT * FROM products
WHERE EXISTS (
SELECT 1
FROM attributes_products
WHERE products.id = product_id
GROUP BY product_id
HAVING (array_agg(attibute_id) @> ARRAY[90,93])
)
The 90,93 is the id of your attributes
The sqlfiddle is here
More details on the array function can be found in
Array Functions and Operators,
Aggregate Functions
Upvotes: 0
Reputation: 1258
Something like this should do it.
SELECT p.id, p.name
FROM products p
INNER JOIN attributes_products ap ON ap.product_id = p.id
INNER JOIN attributes a ON ap.attibute_id = a.id
WHERE a.id in (15,17,19,20) --list of attributes selected by user
GROUP BY p.id, p.name
HAVING COUNT(DISTINCT a.attribute_group_id) = 3
Upvotes: 1