2011-02-16 25 views
8

Tengo dos tablas en mi base de datos:MySQL seleccione Unir dónde y cuando

productos

  • ID (int, clave principal)
  • nombre (varchar)

ProductTags

  • product_id (int)
  • tag_id (int)

me gustaría seleccionar los productos que tienen todas las etiquetas dadas. Probé:

SELECT 
    * 
FROM 
    Products 
JOIN ProductTags ON Products.id = ProductTags.product_id 
WHERE 
    ProductTags.tag_id IN (1, 2, 3) 
GROUP BY 
    Products.id 

pero me da productos que tengan cualquiera de las etiquetas dadas, en lugar de tener todas las etiquetas dadas. Escribir WHERE tag_id = 1 AND tag_id = 2 no tiene sentido, porque no se devolverán filas.

+1

¿No entiendo lo que está buscando? ¿Te importa elaborar con algunos datos y ejemplos? – diagonalbatman

Respuesta

14

Este tipo de problema se conoce como relational division

SELECT Products.* 
FROM Products 
JOIN ProductTags ON Products.id = ProductTags.product_id 
WHERE ProductTags.tag_id IN (1,2,3) 
GROUP BY Products.id /*<--This is OK in MySQL other RDBMSs 
          would want the whole SELECT list*/ 

HAVING COUNT(DISTINCT ProductTags.tag_id) = 3 /*Assuming that there is a unique 
               constraint on product_id,tag_id you 
               don't need the DISTINCT*/ 
+0

Esto resuelve el problema. Me pregunto qué representa el número 3 en la última línea. Obtengo los resultados correctos con: 'HAVING COUNT (DISTINCT ProductTags.tag_id) = 1' y cualquier tamaño de etiquetas id array:' WHERE ProductTags.tag_id IN (1,2,3,4) ' – Darrarski

+0

Muchas gracias, usted eres maestro. – Darrarski

+1

Debería ajustar el '3' según corresponda. Para '(1,2,3,4)' necesitaría usar 'HAVING COUNT (DISTINCT ProductTags.tag_id) = 4'; de lo contrario, se recuperarían los que tenían 3 etiquetas coincidentes de las 4. –

0

es necesario tener un grupo de/recuento para asegurar que todo se contabilizan

select Products.* 
    from Products 
     join (SELECT Product_ID 
        FROM ProductTags 
        where ProductTags.tag_id IN (1,2,3) 
        GROUP BY Products.id 
        having count(distinct tag_id) = 3) PreQuery 
     on ON Products.id = PreQuery.product_id 
0

El MySQL WHERE fieldname IN (1,2,3) es esencialmente la abreviatura de WHERE fieldname = 1 OR fieldname = 2 OR fieldname = 3. Por lo tanto, si no obtiene la funcionalidad deseada con WHERE ... IN, intente cambiar a OR s. Si eso aún no le da los resultados que desea, entonces tal vez WHERE ... IN no es la función que necesita usar.