您建议的entity-attribute-value 模型适合这种情况。
关于过滤查询,您必须了解,使用 EAV 模型会牺牲大量查询能力,因此这会变得相当棘手。然而,这是解决您的问题的一种方法:
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;
这种方法的一个不优雅的特点是您需要指定您希望在sub_t.matches = 2 中匹配的属性/值对的数量。如果我们有三个条件,我们将不得不指定sub_t.matches = 3,等等。
让我们构建一个测试用例:
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');
查询:
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;
结果:
+-------+
| id |
+-------+
| mango |
+-------+
1 row in set (0.02 sec)
现在让我们用color=yellow 和taste=sweet 插入另一个水果:
INSERT INTO stuff VALUES ('pear', 'color', 'yellow');
INSERT INTO stuff VALUES ('pear', 'taste', 'sweet');
INSERT INTO stuff VALUES ('pear', 'origin', 'somewhere');
同样的查询会返回:
+-------+
| id |
+-------+
| mango |
| pear |
+-------+
2 rows in set (0.00 sec)
如果我们想将此结果限制为具有origin=MEXICO 的实体,则必须添加另一个OR 条件并检查sub_t.matches = 3 而不是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;
结果:
+-------+
| id |
+-------+
| mango |
+-------+
1 row in set (0.00 sec)
与每种方法一样,使用 EAV 模型时也有一定的优点和缺点。确保您在应用程序的上下文中广泛研究该主题。您甚至可能需要考虑替代关系数据库,例如Cassandra、CouchDB、MongoDB、Voldemort、HBase、SimpleDB 或其他键值存储。