2009-12-03 3 views
0

J'ai des tables avec des listes, des catégories et un qui les mappe les uns aux autres. Ainsi, une liste peut ensuite être placée dans plusieurs catégories. Quelque chose comme ce qui suit:MySQL retourne des résultats distincts pour plusieurs conditions

listings table 
    id 
    title 
    etc 

categories table 
    id 
    category_name 
    etc 

map table 
    listing_id 
    category_id 

Quand je dois obtenir toutes les informations pour les annonces dans une seule catégorie (dans ce cas, la catégorie avec l'id de 18), les travaux suivants fin:

SELECT * 
FROM (`listings`, `map`) 
WHERE `map`.`category_id` = 18 
AND map.listing_id = listings.id 

Mon problème est comment puis-je faire un type similaire de requête, mais maintenant j'ai besoin de trouver ces listes distinctes qui sont dans deux catégories. Par exemple, que se passe-t-il si je dois renvoyer uniquement les listes distinctes qui sont dans category_id = 18 AND category_id = 20? Cela nécessiterait-il un type de jointure?

+0

Est-ce que vous voulez exclure une liste de votre jeu de résultats si elle est plus que seulement les 2 catégories que vous spécifiez? –

Répondre

2

Oui, vous devez utiliser une autre jointure. Je pense que ce qui suit devrait le faire:

SELECT lst.`id`, lst.<column>, ... 
FROM `listings` lst, `map` m, `map` m2 
WHERE m.`category_id` = 18 AND m2.`category_id` = 20 
AND m.`listing_id` = lst.`id` 
AND m2.`listing_id` = lst.`id` 

Une autre version, inspirée des suggestions de Germ mais celui-ci fonctionne (notez que j'ai remplacé id avec category_id pour plus de clarté):

select l.listing_id 
from listings l 
join (select m.listing_id, count(*) as cnt from map m where 
    m.category_id in (18,20) 
    group by m.listing_id) cat_matches 
    on cat_matches.listing_id = l.listing_id 
where cat_matches.cnt = 2; -- 2 is the number of distinct categories to match 

laid, hein ? Et le subselect pourrait ne pas être tout ce efficace ... mais:


select l.listing_id 
from listings l 
join map m on l.listing_id=m.listing_id 
where m.category_id in (18,20) 
group by l.listing_id 
having COUNT(*)=2; 

Vous pouvez éliminer cette subselect en obtenant toutes les lignes dont vous avez besoin, puis les filtrer. Notez que cette solution suppose que les lignes dans la table de carte sont uniques (ce qui devrait être le cas car le PK doit être défini à la fois sur listing_id et category_id).

+0

Merci beaucoup, a parfaitement fonctionné – Frank

+1

Vous devrez continuer à rejoindre la table de la carte chaque fois que vous avez besoin d'une catégorie différente avec cette méthode – Germ

+0

D'accord, la solution de Germ est probablement une meilleure pour ce problème. –

1

Cela devrait fonctionner

select * from listings l 
join map m on m.listing_id = l.id 
join categories c on c.id = m.category_id 
where c.id in (18, 20) 
+0

+1 pour les jointures correctes! –

+0

@pcampbell: SQL99 JOINs est plus précis –

+0

Merci pour votre aide, j'ai eu quelques problèmes pour que cela fonctionne. – Frank

0

Que diriez-vous ... ce

select * from listings l, map m, categories c 
where l.id = m.listing_id 
and m.category_id = c.id 
and (c.id = 18 
or c.id = 20) 

ou

select * from listings l, map m, categories c 
where l.id = m.listing_id 
and m.category_id = c.id 
and c.id in (18, 20) 
+0

Cela ne fonctionnera même pas, vous ne pouvez pas avoir deux clauses 'WHERE' dans une seule requête. –

+0

Vous obtenez le point :) fixe – Germ

Questions connexes