El entity-attribute-value modelo que usted sugiere podría encajar en este escenario.
Con respecto a la consulta de filtrado, debe comprender que con el modelo EAV sacrificará mucho poder de consulta, por lo que esto puede volverse bastante complicado. Sin embargo, esta es una forma de abordar su 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 debe especificar la cantidad de pares de atributo/valor que espera que coincidan en sub_t.matches = 2
. Si tuviéramos tres condiciones, tendríamos que especificar sub_t.matches = 3
, y así sucesivamente.
Construyamos 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 insertemos 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 agregar otro OR
condición y verifique sub_t.matches = 3
en lugar de 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 todo enfoque, existen ciertas ventajas y desventajas cuando se utiliza el modelo EAV. Asegúrese de investigar el tema extensamente en el contexto de su aplicación. Incluso puede considerar una base de datos relacional alternativa, como Cassandra , CouchDB , MongoDB , Voldemort , HBase , SimpleDB u otras tiendas clave-valor.