2010-05-11 5 views
2

Je les tableaux suivants:
personne, { "id", "Nom", "LastName"}
sports, { "id" "Nom", "Type"}
SportsPerPerson, { "id", "PersonId", "SportsId"}Cette requête sql peut-elle être simplifiée?

Pour ma recherche je veux obtenir toutes les personnes qui excisent un sport spécifique alors que j'ai seulement l'attribut Sports "Nom" à ma disposition. Pour récupérer les lignes correctes j'ai compris les requêtes suivantes:

SELECT * 
FROM Person 
WHERE Person.Id in 
(
    SELECT SportsPerPerson.PersonId FROM SportsPerPerson 
    INNER JOIN Sports on SportsPerPerson.SportsId = Sports.Id 
    WHERE Sports.Name = 'Tennis' 
) 
AND Person.Id in 
(
    SELECT SportsPerPerson.PersonId FROM SportsPerPerson 
    INNER JOIN Sports on SportsPerPerson.SportsId = Sports.Id 
    WHERE Sports.Name = 'Soccer' 
) 

OU

SELECT * 
FROM Person 
WHERE Id IN 
    (SELECT PersonId FROM SportsPerPerson WHERE SportsId IN 
     (SELECT Id FROM Sports WHERE Name = 'Tennis')) 
AND Id IN 
    (SELECT PersonId FROM SportsPerPerson WHERE SportsId IN 
     (SELECT Id FROM Sports WHERE Name = 'Soccer')) 

Maintenant, ma question est, est pas là un moyen plus facile d'écrire cette requête? Utiliser juste OU ne fonctionnera pas parce que j'ai besoin de la personne qui joue 'Tennis' ET 'Soccer'. Mais utiliser AND ne fonctionne pas non plus car les valeurs ne sont pas sur la même ligne.

Répondre

1

Vous devez utiliser deux jointures dans la requête:

SELECT * 
FROM Person p INNER JOIN SportsPerPerson spp1 ON (p.PersonId = spp1.PersonId) 
       INNER JOIN Sports s1 ON (s1.SportsIN = spp1.SportId) 
       INNER JOIN SportsPerPerson spp2 ON (p.PersonId = spp2.PersonId) 
       INNER JOIN Sports s2 ON (s2.SportId = spp2.SportId) 
    WHERE s1.Name = 'Tennis' AND s2.Name='Soccer' 
+0

Celui-ci fait l'affaire:] – Bas

2

Vous pouvez utiliser un autre JOIN pour éviter la deuxième IN. Le sous-sélection renvoie uniquement les personnes qui jouent à la fois tennis et de soccer:

SELECT * 
FROM Person 
WHERE Person.Id IN 
(
    SELECT spp1.PersonId 
    FROM SportsPerPerson spp1 
    JOIN SportsPerPerson spp2 ON (spp2.PersonId = spp1.PersonId) 
    JOIN Sports s1 on spp1.SportsId = s1.Id 
    JOIN Sports s2 on spp2.SportsId = s2.Id 
    WHERE s1.Name = 'Tennis' 
     AND s2.Name = 'Soccer' 
) 
+0

Félicitations pour 10K. :) –

+0

@Mark: Merci! Devinez nous allons vous féliciter bientôt sur 50K? :) –

+0

Curieusement, la requête renvoie 0 enregistrements: o J'aime bien l'idée mais je l'ai juste testé et il ne semble pas fonctionner. Il renvoie 0 enregistrements, où mes propres requêtes renvoient 55>. < – Bas

0

L'astuce consiste à utiliser des alias pour que vous puissiez utiliser les mêmes tables plusieurs fois:

SELECT p.* 
FROM Person p 
INNER JOIN SportsPerPerson spa 
    ON p.Id = spa.PersonId 
INNER JOIN Sports sa 
    ON spa.SportsId = sa.Id 
INNER JOIN SportsPerPerson spb 
    ON p.Id = spb.PersonId 
INNER JOIN Sports sb 
    ON spb.SportsId = sb.Id 
WHERE 
    sa.Name = 'Tennis' 
    AND sb.Name = 'Soccer' 
0

ceci:

SELECT * 
FROM Person p 
WHERE (
     SELECT COUNT(*) 
     FROM Sports s 
     JOIN SportsPerPerson sp 
     ON  sp.SportsID = s.id 
     WHERE s.name IN ('Tennis', 'Soccer') 
       AND sp.PersonID = p.id 
     ) = 2 

ou ceci:

SELECT p.* 
FROM (
     SELECT sp.PersonID 
     FROM Sports s 
     JOIN SportsPerPerson sp 
     ON  sp.SportsID = s.id 
     WHERE s.name IN ('Tennis', 'Soccer') 
     GROUP BY 
       sp.PersonID 
     HAVING COUNT(*) = 2 
     ) q 
JOIN person p 
ON  p.id = q.personID 

Vous devez déclarer un UNIQUE KEY ou un PRIMARY KEY sur SportsPerPerson (sportsid, personid) pour que cela fonctionne correctement et rapidement.

0

La requête dont vous avez besoin est:

SELECT p.ID, p.Name, p.LastName 
FROM Person p 
JOIN SportsPerPerson sp ON p.ID = sp.PersonID 
JOIN Sports s ON sp.SportsID = s.ID 
WHERE s.Name = 'Football' 

Cela dit, en aparté, la clé d'identification sur la table SportsPerPerson est tout à fait inutile de mettre en œuvre la relation plusieurs à plusieurs que vous avez. Utiliser les colonnes PersonID et SportID comme une clé primaire composite serait suffisant.

+0

Cela ne m'aide pas vraiment ... Si j'ajoute un autre sport, ce qui est mon intention, il me renvoie 0 records car les sports ne sont pas dans la même rangée. Aussi OU ne m'aidera pas car alors il faudra aussi renvoyer les personnes qui ont soit 'Soccer' ou 'Tennis' et j'ai besoin des deux – Bas