2009-07-09 6 views
1

J'ai une table dans ma base de données:Sélectionnez des valeurs dans SQL qui ne disposent pas d'autres valeurs correspondantes, sauf ceux que je recherche pour

Name | Element 
1   2 
1   3 
4   2 
4   3 
4   5 

Je dois faire une requête pour un certain nombre d'arguments sélectionnera la valeur de Nom qui a à droite ces et seulement ces valeurs. E.g .: arguments sont 2 et 3, la requête devrait retourner seulement 1 et non 4 (parce que 4 a également 5). Pour les arguments 2,3,5 devrait retourner 4.

Ma requête ressemble à ceci:

SELECT name FROM aggregations WHERE (element=2 and name in (select name from aggregations where element=3)) 

Que dois-je ajouter à cette requête pour le faire revenir 4 pas?

Répondre

8

Une façon simple de le faire:

SELECT name 
FROM aggregations 
WHERE element IN (2,3) 
GROUP BY name 
HAVING COUNT(element) = 2 

Si vous voulez ajouter plus, vous devrez changer à la fois la partie IN (2,3) et la partie HAVING:

SELECT name 
FROM aggregations 
WHERE element IN (2,3,5) 
GROUP BY name 
HAVING COUNT(element) = 3 

Une plus robuste façon serait de vérifier tout ce qui n'est pas dans votre jeu:

SELECT name 
FROM aggregations 
WHERE NOT EXISTS (
    SELECT DISTINCT a.element 
    FROM aggregations a 
    WHERE a.element NOT IN (2,3,5) 
    AND a.name = aggregations.name 
) 
GROUP BY name 
HAVING COUNT(element) = 3 

Ce n'est pas très efficace, cependant.

+0

Si l'élément est '2' et '4', il correspondrait à la fois au critère where et the having, non ...? –

+0

Je suis d'accord, cela fonctionnera bien. – tekBlues

+0

@d: Vous avez raison, en fait. Cela couvre les supersets mais pas les sous-ensembles. Semblait rendre Grin heureux, cependant. – Welbog

0

Ceci n'est pas testé, mais habituellement je le ferais avec une requête dans ma clause where pour une petite quantité de données. Notez que ceci n'est pas efficace pour les grands nombres d'enregistrements.

SELECT ag1.Name FROM aggregations ag1 
WHERE ag1.Element IN (2,3) 
AND 0 = (select COUNT(ag2.Name) 
    FROM aggregatsions ag2 
    WHERE ag1.Name = ag2.Name 
     AND ag2.Element NOT IN (2,3) 
) 
GROUP BY ag1.name; 

Cela dit: « Donnez-moi tous les noms qui ont les éléments que je veux, mais ont aucun enregistrement avec des éléments que je ne veux pas »

1

Créer une table temporaire, remplissez-le avec vos valeurs et requête comme ceci:

SELECT name 
FROM (
     SELECT DISTINCT name 
     FROM aggregations 
     ) n 
WHERE NOT EXISTS 
     (
     SELECT 1 
     FROM (
       SELECT element 
       FROM aggregations aii 
       WHERE aii.name = n.name 
       ) ai 
     FULL OUTER JOIN 
       temptable tt 
     ON  tt.element = ai.element 
     WHERE ai.element IS NULL OR tt.element IS NULL 
     ) 

Ceci est plus efficace que l'utilisation COUNT(*), car il arrêtera la vérification d'un name dès qu'il trouve la première ligne qui ne dispose pas d'un match (soit dans aggregations ou temptable)

Questions connexes