Questo è un caso di divisione relazionale:
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;
Abbiamo raccolto un arsenale di tecniche rilevanti qui:
Controlla un gran numero di proprietà
Puoi espandere la query di cui sopra e per una manciata di proprietà sarà tra le soluzioni più veloci possibili. Per un numero maggiore sarà più conveniente (e anche iniziando ad essere più veloce) percorrere questa strada:
Esempio per 5 proprietà, espandi se necessario:
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);
Il passaggio aggiuntivo della sottoquery interna cp1
è solo necessario, perché ovviamente hai più voci per (component_id, property_id)
in components_componentproperty
. Potremmo piega cp1
e cp2
in uno e controlla
HAVING count(DISTINCT property_id) = 5
Ma mi aspetto che sia più costoso, dal momento che count(DISTINCT col)
necessita di un'operazione di ordinamento per riga .
Per liste molto lunghe IN
è una cattiva scelta. Considera: