Beaucoup à plusieurs requêtes de table
Question
J'ai plusieurs tables d'index et je souhaite effectuer une requête de type inclusion / exclusion.
fid est vraiment un index entier, mais ici sous forme de lettres pour en faciliter la compréhension. Voici un exemple de tableau:
table t
eid | fid
----+----
1 | A
1 | B
1 | C
2 | B
2 | C
3 | A
3 | C
4 | A
4 | B
5 | B
Voici quelques exemples de requêtes que je souhaite.
- Quels sont les eids fid B et PAS A? (Réponses 2 et 5)
- Quels eids ont fid C et PAS A? (Réponse eid 2)
Je n'arrive pas à trouver une requête qui le fasse.
J'ai essayé une auto-jointure comme ceci:
select *
from t as t1
join t as t2
where t1.eid=t2.eid
and t1.fid!=t2.fid
and t1.fid=B and t2.fid!=A
Cela ne fonctionnera pas car il renverra toujours les lignes où eid = 1 et fid = C.
Suis-je clair sur ce que je veux?
La solution
Voici un exemple de requête pour 1 (2 fonctionne à peu près de la même manière)
select t1.eid
from t t1
where t1.fid = 'B'
and not exists
(select 1
from t t2
where t2.eid = t1.eid
and t2.fid = 'A')
Autres conseils
Utilisez définir la soustraction
.Select eid from t where fid = 'B' EXCEPT select eid from t where fid = 'A'
Vous pouvez utiliser une sous-sélection
sélectionnez eid de t où fid = 'C' et eid not in (sélectionnez eid de t où fid = 'A')
MySQL 5.0 soutient le où existe / existe pas, comme décrit par Nigel et Mike.
Version avec des jointures droites qui peuvent être plus rapides qu'avec EXISTS:
Select t1.eid From #test t1 left join ( Select eid From #test t2 Where fid = 'A' Group by eid ) t2 on t2.eid = t1.eid Where t1.fid = 'B' and t2.eid is null
Cela devrait être possible sans utiliser de sous-requête:
SELECT DISTINCT t1.eid
FROM table1 AS t1
LEFT JOIN table1 AS t2 ON (t1.eid = t2.eid AND t2.fid = 'A')
WHERE t2.eid IS NULL
AND t1.fid = 'B';
Pour effectuer votre deuxième exemple de recherche, modifiez simplement la valeur "B" en "C".
Regardez dans l'opérateur MINUS. Cela fonctionne comme UNION, sauf qu’il soustrait l’ajout de UNION. La réponse précédente avec le mot "EXCEPT" peut être un mot clé différent pour la même chose.
Voici une réponse non testée:
select eid
from t
where fid = 'A'
minus
select eid
from t
where fid = 'B'