Pregunta
Tengo una tabla de índice de muchos a muchos, y quiero hacer una consulta de tipo incluir / excluir en ella.
fid es realmente un índice entero, pero aquí como letras para una comprensión más fácil. Aquí hay una tabla de muestra:
tabla t
eid | fid
----+----
1 | A
1 | B
1 | C
2 | B
2 | C
3 | A
3 | C
4 | A
4 | B
5 | B
Aquí hay algunas consultas de muestra que quiero.
- ¿Qué eids tienen fid B y NO A? (Responda eid 2 y 5)
- ¿Qué eids tienen fid C y NO A? (Respuesta eid 2)
Parece que no puedo resolver una consulta que haga esto.
He intentado una autounión como esta:
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
Eso no funcionará, porque aún devolverá filas donde eid = 1 y fid = C.
¿Tengo claro lo que quiero?
Solución
Aquí hay un ejemplo de una consulta para 1 (2 funciona de la misma manera)
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')
Otros consejos
Select eid from t where fid = 'B' EXCEPT select eid from t where fid = 'A'
Puedes usar una sub-selección
seleccione eid desde t donde fid = 'C' y eid no está dentro (seleccione eid desde t donde fid = 'A')
MySQL 5.0 admite dónde existe / dónde no existe, según lo descrito por Nigel y Mike.
Versión con combinaciones directas que puede ser más rápida que usar 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
Debería ser posible hacer esto sin usar una subconsulta:
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';
Para hacer su segunda búsqueda de ejemplo, simplemente cambie el valor 'B' a 'C'.
Mire en el operador MENOS. Funciona como UNION, excepto que resta donde UNION agrega. La respuesta anterior con la palabra "EXCEPTO" puede ser una palabra clave diferente para la misma cosa.
Aquí hay una respuesta no probada:
select eid
from t
where fid = 'A'
minus
select eid
from t
where fid = 'B'