2011-01-21 18 views
10

Tengo lo que parece ser un problema simple, pero no puedo encontrar la solución adecuada a través de SQL. Estoy usando postgresql específicamente.Pregunta SQL donde TODOS los registros en una unión coinciden con una condición?

tome las siguientes:

SELECT * FROM users INNER JOIN tags ON (tags.user_id = users.id) WHERE tags.name IN ('word1', 'word2') 

Esto no hace lo que necesito. Quiero encontrar usuarios cuyas etiquetas SÓLO están incluidas en la lista. Si el usuario tiene una etiqueta que no está en la lista, el usuario no debe ser incluido.

etiquetas 'usuario1': word1, palabra2, word3
etiquetas '' usuario2: word1
etiquetas '' user3: palabra1, palabra2

Dado: palabra1 y palabra2. Quiero preparar una consulta que devuelva 'user2' y 'user3'. 'user1' está excluido porque tiene una etiqueta que no está en la lista.

Espero haber dejado esto en claro. ¡Gracias por tu ayuda!

+2

posible duplicado de [? SQL, cómo hacer coincidir TODO] (http://stackoverflow.com/questions/4763143/sql-how-to-match -all) –

+0

¿No acabas de preguntar esto –

+0

¿Deberían devolverse los usuarios que no tienen ninguna etiqueta? – Quassnoi

Respuesta

6

Basándose en COUNT (*) = 2, será necesario que no puede haber duplicados de user_id y el nombre en la tabla de etiquetas. Si ese es el caso, iría por esa ruta. De lo contrario, esto debería funcionar:

SELECT u.* 
FROM users AS u 
WHERE u.id NOT IN (
    SELECT DISTINCT user_id FROM tags WHERE name NOT IN ('word1', 'word2') 
) AND EXISTS (SELECT user_id FROM tags WHERE user_id = u.id) 
+2

Esto * puede * incluir usuarios sin etiquetas. –

+0

@Andriy M: Tiene razón. He actualizado mi respuesta para dar cuenta de esto ahora. Gracias por señalarlo. – nybbler

+0

'DISTINCT' es solo una sobrecarga adicional aquí ... – JNK

1
SELECT user_id 
FROM users 
WHERE id IN 
     (
     SELECT user_id 
     FROM tags 
     ) 
     AND id NOT IN 
     (
     SELECT user_id 
     FROM tags 
     WHERE name NOT IN ('word1', 'word2') 
     ) 

o

SELECT u.* 
FROM (
     SELECT DISTINCT user_id 
     FROM tags 
     WHERE name IN ('word1', 'word2') 
     ) t 
JOIN users u 
ON  u.id = t.user_id 
     AND t.user_id NOT IN 
     (
     SELECT user_id 
     FROM tags 
     WHERE name NOT IN ('word1', 'word2') 
     ) 
+0

Esto devolverá todos los usuarios que coinciden con ambas palabras, sin verificar si no coinciden con otras palabras. Esto no responde la pregunta. – GolezTrol

+0

@GolezTrol: entendí mal la tarea, gracias por señalar. – Quassnoi

0

para obtener todos los usuarios que no tienen una etiqueta que no está en la lista, utilice la siguiente consulta. Podría ser que se devuelva a los usuarios que no tienen etiqueta o solo una etiqueta que coincida con las palabras, pero entiendo que es la funcionalidad deseada.

SELECT 
    u.* 
FROM 
    users u 
    LEFT JOIN tags t 
    ON t.user_id = u.userid AND 
     t.name NOT IN ('word1', 'word2') 
WHERE 
    t.user_id IS NULL 
0
SELECT u.* 
FROM users u 
INNER JOIN (
    SELECT user_id FROM tags WHERE name IN ('word1', 'word2') 
    EXCEPT 
    SELECT user_id FROM tags WHERE name NOT IN ('word1', 'word2') 
) s ON u.id = s.user_id 
0
SELECT distinct users.id 
FROM users 
INNER JOIN tags ON (tags.user_id = users.id) 
group by users.id 
having count(*) = 2 
and min(tags.name) = 'word1' 
and max(tags.name) = 'word2' 
+1

¿Podría darnos alguna explicación sobre por qué su consulta es mejor que la que ya se publicó? – Theresa

Cuestiones relacionadas