The entity-attribute-value model that you propose can fit in this scenario.
As for the filtering query, you should understand that with the EAV model you will sacrifice a lot of query power, so this can become quite complicated. However, this way to solve your problem:
SELECT stuff.id FROM stuff JOIN (SELECT COUNT(*) matches FROM table WHERE (`key` = X1 AND `value` = V1) OR (`key` = X2 AND `value` = V2) GROUP BY id ) sub_t ON (sub_t.matches = 2 AND sub_t.id = stuff.id) GROUP BY stuff.id;
One of the inelegant features of this approach is that you need to specify the number of attribute / value pairs that you expect to combine in sub_t.matches = 2 . If we had three conditions, we would have to specify sub_t.matches = 3 , etc.
Let's build a test case:
CREATE TABLE stuff (`id` varchar(20), `key` varchar(20), `value` varchar(20)); INSERT INTO stuff VALUES ('apple', 'color', 'red'); INSERT INTO stuff VALUES ('mango', 'color', 'yellow'); INSERT INTO stuff VALUES ('banana', 'color', 'yellow'); INSERT INTO stuff VALUES ('apple', 'taste', 'sweet'); INSERT INTO stuff VALUES ('mango', 'taste', 'sweet'); INSERT INTO stuff VALUES ('banana', 'taste', 'bitter-sweet'); INSERT INTO stuff VALUES ('apple', 'origin', 'US'); INSERT INTO stuff VALUES ('mango', 'origin', 'MEXICO'); INSERT INTO stuff VALUES ('banana', 'origin', 'US');
Query:
SELECT stuff.id FROM stuff JOIN (SELECT COUNT(*) matches, id FROM stuff WHERE (`key` = 'color' AND `value` = 'yellow') OR (`key` = 'taste' AND `value` = 'sweet') GROUP BY id ) sub_t ON (sub_t.matches = 2 AND sub_t.id = stuff.id) GROUP BY stuff.id;
Result:
+-------+ | id | +-------+ | mango | +-------+ 1 row in set (0.02 sec)
Now add another fruit with color=yellow and taste=sweet :
INSERT INTO stuff VALUES ('pear', 'color', 'yellow'); INSERT INTO stuff VALUES ('pear', 'taste', 'sweet'); INSERT INTO stuff VALUES ('pear', 'origin', 'somewhere');
The same request will be returned:
+-------+ | id | +-------+ | mango | | pear | +-------+ 2 rows in set (0.00 sec)
If we want to limit this result to entities using origin=MEXICO , we will need to add another OR condition and check sub_t.matches = 3 instead of 2 .
SELECT stuff.id FROM stuff JOIN (SELECT COUNT(*) matches, id FROM stuff WHERE (`key` = 'color' AND `value` = 'yellow') OR (`key` = 'taste' AND `value` = 'sweet') OR (`key` = 'origin' AND `value` = 'MEXICO') GROUP BY id ) sub_t ON (sub_t.matches = 3 AND sub_t.id = stuff.id) GROUP BY stuff.id;
Result:
+-------+ | id | +-------+ | mango | +-------+ 1 row in set (0.00 sec)
As with every approach, there are certain advantages and disadvantages to using the EAV model. Make sure you carefully study the topic in the context of your application. You might even want to consider alternative relational databases such as Cassandra , CouchDB , MongoDB , Voldemort , HBase , SimpleDB, or other key stores.