2013-08-22 5 views
1

J'ai trois tables produits, propriétés et product_properties. Le sous-ensemble des structures de table et les valeurs sont indiquées ci-dessous:Requête MySQL avec plusieurs conditions et plusieurs tables

products 
--------------------------------------------- 
| id | name | description | price | 
--------------------------------------------- 
| 1 | Camera | Color Camera | 100 | 
| 2 | Lens 1 | Camera Lens 1 | 20 | 
| 3 | Lens 2 | Camera Lens 2 | 30 | 
--------------------------------------------- 

properties 
------------------------------------------ 
| id | name   | display  | 
------------------------------------------ 
| 1 | lens_mount | Lens Mount | 
| 2 | image_circle | Image Circle | 
| 3 | focal_length | Focal Length | 
| 4 | lens_family | Lens Family | 
------------------------------------------ 

product_properties 
------------------------------------------------ 
| id | value | product_id | property_id | 
------------------------------------------------ 
| 1 | F-Mount | 2   | 1   | 
| 2 | C-Mount | 3   | 1   | 
| 3 | 42.01 mm | 2   | 2   | 
| 4 | 13.00 mm | 3   | 2   | 
| 5 | 10.00 | 2   | 3   | 
| 6 | 12.00 | 3   | 3   | 
| 7 | Standard | 1   | 4   | 
| 8 | Standard | 2   | 4   | 
| 9 | Standard | 3   | 4   | 
------------------------------------------------ 

Voici ma condition de sortie:

Trouver tous les objectifs pour appareil photo 1 (caméra match et l'objectif par lens_family, qui est « Standard » ici) qui ont lens_mount = 'F-Mount' et image_circle> = 40 mm et focal_length> 5

J'ai essayé requête suivante pour cela:

SELECT * FROM products 
    INNER JOIN product_properties ON products.id = product_properties.product_id 
    INNER JOIN properties ON properties.id = product_properties.property_id 
    WHERE (product_properties.value = 'Standard') 
    AND (properties.name = 'lens_mount' AND product_properties.value = 'F-Mount') 
    AND (properties.name = 'image_circle' AND product_properties.value >= ABS('40 mm')) 
    AND (properties.name = 'focal_length' AND product_properties.value >= 5) 

Toutefois, cette requête donne uniquement un résultat correct s'il n'y a qu'une seule condition. Avec toutes les conditions, cela ne donne aucune valeur. J'ai essayé avec OU à la place de ET dans la condition où, mais cela n'a pas aidé à obtenir la sortie correcte.

Quelqu'un peut-il trier ce s'il vous plaît. Merci d'avance.

Répondre

2

Vous voulez faire la logique dans la clause having plutôt que dans la clause where:

SELECT products.id 
FROM products 
    INNER JOIN product_properties ON products.id = product_properties.product_id 
    INNER JOIN properties ON properties.id = product_properties.property_id 
group by products.id 
having sum(properties.name = 'lens_family' AND product_properties.value = 'Standard') > 0 and 
     sum(properties.name = 'lens_mount' AND product_properties.value = 'F-Mount') > 0 and 
     sum(properties.name = 'image_circle' AND product_properties.value >= ABS('40 mm')) > 0 and 
     sum(properties.name = 'focal_length' AND product_properties.value >= 5) > 0; 

Vous êtes à la recherche d'un ensemble de propriétés sur un seul produit. Aucune rangée ne peut correspondre à toutes les conditions - elles sont en conflit les unes avec les autres. Au lieu de cela, utilisez la clause group by pour regrouper les lignes pour un produit donné. Ensuite, comptez le nombre de lignes correspondant à chaque condition.

Chaque clause du having correspond à l'une de vos clauses d'origine dans l'instruction where, encadrée par sum(). Cela compte le nombre de lignes qui correspondent. Les conditions garantissent qu'il y a au moins une ligne pour chaque propriété.

+0

J'aime cette solution. Vous devez probablement ajouter 'properties.name = 'lens_family' AND' à votre premier critère de clause 'HAVING' (' product_properties.value = 'Standard'') dans le cas où différentes propriétés pourraient avoir la valeur' ​​Standard '. – Tom

+0

@Tom. . . Très bon point. J'ai fait cette correction. –

+0

Merci Gordon & Tom, cette solution a parfaitement fonctionné! – Lalu

0

Ah, le schéma EVA tant redouté. La première chose que vous devriez faire est de créer une vue pour normaliser les données selon le SQL suivant.

Vous pouvez ensuite utiliser deux copies de cette vue (une pour l'appareil photo, une pour l'objectif) et les assembler pour obtenir ce dont vous avez besoin.

SELECT p.id 
     ,p.name 
     ,pp1.value as Lens_Mount 
     ,pp2.value as Image_Circle 
     ,pp3.value as Focal_Length 
     ,pp4.value as Lens_Family 
from products p 
left outer join 
     product_properties pp1 
on  pp1.product_id = p.id 
and  pp1.property_id = 1 --lens Mount 
left outer join 
     product_properties pp2 
on  pp2.product_id = p.id 
and  pp2.property_id = 2 --Image Circle 
left outer join 
     product_properties pp3 
on  pp3.product_id = p.id 
and  pp3.property_id = 3 --Focal Length 
left outer join 
     product_properties pp4 
on  pp4.product_id = p.id 
and  pp4.property_id = 3 --Lens Family   
where p.name like 'Lens%' 
0

Vous devez OU chaque condition et compter combien d'entre eux sont satisfaits pour chaque ID_produit. Donc vous GROUP BY product_id et filtrez les résultats en utilisant la clause HAVING. Notez qu'il peut être difficile de comparer des valeurs de propriété qui sont des chaînes si vous avez vraiment besoin d'une comparaison numérique.