C'est un cas de division relationnelle :
SELECT c.id, c.name
FROM components_componentproperty cp1
JOIN components_componentproperty cp2 USING (component_id)
JOIN components_component c ON c.id = cp1.component_id
WHERE cp1.property_id = 9102 AND cp1.value IN ('4015', '4016')
AND cp2.property_id = 8801 AND cp2.value = '3'
AND c.type_id = 3832
GROUP BY c.id;
Nous avons rassemblé ici un arsenal de techniques pertinentes :
Recherchez un grand nombre de propriétés
Vous pouvez développer la requête ci-dessus et pour une poignée de propriétés, ce sera parmi les solutions les plus rapides possibles. Pour un plus grand nombre, il sera plus pratique (et commence également à être plus rapide) d'emprunter cette route :
Exemple pour 5 propriétés, développez si nécessaire :
SELECT c.id, c.name
FROM (
SELECT id
FROM (
SELECT component_id AS id, property_id -- alias id just to shorten syntax
FROM components_componentproperty
WHERE property_id IN (9102, 8801, 1234, 5678, 9876) -- expand as needed
GROUP BY 1,2
) cp1
GROUP BY 1
HAVING count(*) = 5 -- match IN expression
) cp2
JOIN components_component c USING (id);
L'étape supplémentaire de la sous-requête interne cp1
est seulement nécessaire, car vous avez évidemment plusieurs entrées par (component_id, property_id)
dans components_componentproperty
. Nous pourrions plier cp1
et cp2
en un et vérifiez
HAVING count(DISTINCT property_id) = 5
Mais je m'attends à ce que ce soit plus cher, car count(DISTINCT col)
nécessite une opération de tri par ligne .
Pour les très longues listes IN
est un mauvais choix. Considérez :