El modelo entity-attribute-value que sugiere puede encajar en este escenario.
En cuanto a la consulta de filtrado, debe comprender que con el modelo EAV sacrificará un montón de potencia de consulta, por lo que esto puede ser bastante complicado. Sin embargo ésta manera de abordar el 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 característica poco elegante de este enfoque es que es necesario especificar el número de pares/valor de atributo que espera igualar en sub_t.matches = 2
. Si tuviéramos tres condiciones, tendríamos que especificar sub_t.matches = 3
, y así sucesivamente.
Vamos a construir un caso de prueba:
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');
Consulta:
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;
Resultado:
+-------+
| id |
+-------+
| mango |
+-------+
1 row in set (0.02 sec)
Ahora vamos a insertar otra fruta con color=yellow
y taste=sweet
:
INSERT INTO stuff VALUES ('pear', 'color', 'yellow');
INSERT INTO stuff VALUES ('pear', 'taste', 'sweet');
INSERT INTO stuff VALUES ('pear', 'origin', 'somewhere');
La misma consulta devolvería:
+-------+
| id |
+-------+
| mango |
| pear |
+-------+
2 rows in set (0.00 sec)
Si queremos restringir este resultado a entidades con origin=MEXICO
, tendríamos que añadir otra condición OR
y comprobar si en lugar de 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;
Resultado:
+-------+
| id |
+-------+
| mango |
+-------+
1 row in set (0.00 sec)
Como en cada enfoque, hay ciertas ventajas y desventajas cuando se utiliza el modelo de EAV. Asegúrese de investigar extensamente el tema en el contexto de su aplicación. Es posible que desee considerar una base de datos relacional alternativa, como Cassandra, CouchDB, MongoDB, Voldemort, HBase, SimpleDB u otras tiendas de valores-clave.
es para mi sorpresa que Reddit utiliza ampliamente EVA. http://carsonified.com/blog/dev/steve-huffman-on-lessons-learned-at-reddit/ – crapbag