Este é um caso de divisão relacional:
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;
Reunimos aqui um arsenal de técnicas relevantes:
Verifique se há um grande número de propriedades
Você pode expandir a consulta acima e, para uma mão cheia de propriedades, estará entre as soluções mais rápidas possíveis. Para um número maior será mais conveniente (e também começando a ser mais rápido) seguir este caminho:
Exemplo para 5 propriedades, expanda conforme necessário:
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);
A etapa extra da subconsulta interna
cp1
só é necessário, porque você obviamente tem várias entradas por (component_id, property_id)
em components_componentproperty
. Nós poderíamos dobrar cp1
e cp2
em um e verifique HAVING count(DISTINCT property_id) = 5
Mas espero que seja mais caro, pois
count(DISTINCT col)
precisa de uma operação de classificação por linha . Para listas muito longas
IN
é uma má escolha. Considerar: