views:

45

answers:

5

I'm having a problem with fetching some data.
The tables I have (for testing purposes):

Products:

product_id      | product_name
-----------------------------
1               | product 1
2               | product 2
3               | product 3

Attributes:

product_id      | attribute_id      | attribute_value
-------------------------------------------------------
1               | 1                 | lorem
1               | 2                 | ipsum
2               | 1                 | lorem
2               | 2                 | doler
3               | 1                 | sit
3               | 2                 | ipsum

I want to find the products that have lorem stored in attribute_id 1 AND ipsum stored in attribute_id 2.

If I use this query,

SELECT
   attributes.attribute_id,
   attributes.attribute_value,
   products.product_id
FROM
   products
   Inner Join attributes ON products.product_id = attributes.product_id
WHERE
   (attributes.attribute_id = 1 AND attributes.attribute_value = 'lorem')
OR
   (attributes.attribute_id = 2 AND attributes.attribute_value = 'ipsum')

I get:

attribute_id         | attribute_value     | product_id
----------------------------------------------------------
1                    | lorem               | 1
2                    | ipsum               | 1
1                    | lorem               | 2
2                    | lorem               | 3

But I really want to get this result:

attribute_id_1 | attribute_id_2 | attribute_value_1 | attribute_value_2 | product_id
----------------------------------------------------------
1              | 2              | lorem             | ipsum             | 1

Or just product_id 1 as a result.

I can get it working with the next query, but in production (with a lot of data and a few more joins) this is WAY to slow.

SELECT
   products.product_id
FROM
   products
   Inner Join attributes ON products.product_id = attributes.product_id
WHERE
   attributes.attribute_value = 'ipsum'
AND
   products.product_id IN (
      SELECT
         products.product_id
      FROM
         products
         Inner Join attributes ON products.product_id = attributes.product_id
      WHERE
         attributes.attribute_value =  'lorem'
)

I hope you understand what I'm trying to do.

Can someone please help me?
Thanks!

A: 

Could you take the first (broken) query, group by product_id and then add a HAVING COUNT(*) = 2 clause?

pdbartlett
This may work.. If Brian's answer doesn't work, I'll try this. Thanks!
Johan
No problem :) Good luck...
pdbartlett
Well, because my production setup is a bit more complicated than my example, your answer works and is the best option for me. Thanks again.
Johan
A: 

Quote:

attribute_id_1 | attribute_id_2 | attribute_value_1 | attribute_value_2 | product_id
----------------------------------------------------------
1              | 2              | lorem             | ipsum             | 1

I think you can't create dynamic fields.. i don't see why you would fetch your data that way? Why don't you simply do something like :

select Products.* from Products,Attributes WHERE
Products.product_id = Attributes.product_id
AND ((Attributes.attribute_value='ipsum' AND Attributes.attribute_id='1') OR (Attributes.attribute_value='lorem'  AND  Attributes.attribute_id='2')) GROUP by Products.product_id;
youssef azari
I need to find the products where lorem is stored in attribute_id 1 AND ipsum stored in attribute_id 2, not OR like in my example. With this query I get them all. But thanks for the reply.
Johan
Then use 'QUERY 1' UNION 'QUERY 2'see MySQL doc on UNION.
youssef azari
A: 
SELECT * FROM products p
INNER JOIN attributes a USING (product_id)
WHERE a.attribute_value IN ('lorem','ipsum')
Zane Edward Dockery
This way I get all products, not the ones with both values.
Johan
A: 

Since the first four columns are all fixed, there's no need to select them. All you need is the product id; you can get this by...

SELECT product_id
    FROM products
    WHERE EXISTS (SELECT *
                      FROM attributes
                      WHERE attributes.product_id      = products.product_id AND
                            attributes.attribute_id    = 1                   AND
                            attributes.attribute_value = 'lorem')
                  AND
          EXISTS (SELECT *
                      FROM attributes
                      WHERE attributes.product_id      = products.product_id AND
                            attributes.attribute_id    = 2                   AND
                            attributes.attribute_value = 'ipsum');

If you really must have the fixed columns in your output, you could try...

SELECT 1 AS attribute_id_1,
       2 AS attribute_id_2,
       'lorem' AS attribute_value_1,
       'ipsum' AS attribute_value_2,
       product_id
    FROM ...etc...
Brian Hooper
Hey Brian, I think this is going to work... I'm gonna try to use it in my production database. Thanks!
Johan
This answer is perfect for my the example above, but I can't get it to work in my production environment. But thanks again.
Johan
A: 
Select 
a1.attribute_id attribute_id_1,  
a2.attribute_id attribute_id_2,
a1.attribute_value attribute_value_1,
a2.attribute_value attribute_value_2,
p.product_id
from products p
inner join attributes a1 on a1.product_id = p.product_id and a1.attribute_id = 1 
inner join attributes a2 on a2.product_id = p.product_id and a2.attribute_id = 2
where a1.attribute_value='lorem'
and a2.attribute_value='ipsum';
ceteras