Il modello entity-attribute-value che suggerisci potrebbe rientrare in questo scenario.
Per quanto riguarda la query di filtro, è necessario comprendere che con il modello EAV si sacrifica molta potenza di interrogazione, quindi questo può diventare piuttosto complicato. Tuttavia, questo un modo per affrontare il problema:
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;
Una caratteristica poco elegante di questo approccio è che è necessario specificare il numero di coppie/valore di attributo che si prevede di abbinare in sub_t.matches = 2
. Se avessimo tre condizioni, avremmo dovuto specificare sub_t.matches = 3
e così via.
Costruiamo un banco di prova:
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;
Risultato:
+-------+
| id |
+-------+
| mango |
+-------+
1 row in set (0.02 sec)
Ora inseriamo un altro frutto con color=yellow
e taste=sweet
:
INSERT INTO stuff VALUES ('pear', 'color', 'yellow');
INSERT INTO stuff VALUES ('pear', 'taste', 'sweet');
INSERT INTO stuff VALUES ('pear', 'origin', 'somewhere');
La stessa query restituirebbe:
+-------+
| id |
+-------+
| mango |
| pear |
+-------+
2 rows in set (0.00 sec)
Se vogliamo limitare questo risultato a entità con origin=MEXICO
, avremmo dovuto aggiungere un altro OR
condizioni e verificare la presenza di sub_t.matches = 3
invece di 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;
Risultato:
+-------+
| id |
+-------+
| mango |
+-------+
1 row in set (0.00 sec)
Come in ogni approccio, ci sono alcuni vantaggi e svantaggi quando si utilizza il modello di EAV. Assicurati di effettuare ricerche approfondite sull'argomento nel contesto della tua applicazione. Potresti anche voler considerare un database relazionale alternativo, come Cassandra, CouchDB, MongoDB, Voldemort, HBase, SimpleDB o altri negozi di valore-chiave.
è con sorpresa che Reddit utilizza EVA ampiamente. http://carsonified.com/blog/dev/steve-huffman-on-lessons-learned-at-reddit// – crapbag