2010-01-04 13 views
6

Tengo una aplicación web que combina imágenes con etiquetas, y necesito crear una forma de refinar dinámicamente los resultados para la búsqueda de etiquetas. Sin embargo, no puedo encontrar una forma clara de realizar consultas SQL, y ahí es donde necesito tu ayuda.SQL n-to-n que coincide con varios valores

La idea es que si busco las etiquetas "limpiar" y "perro", tendré resultados de imágenes que tengan las dos etiquetas "limpia" y "perro". Si también incluyo la etiqueta "pequeño", mis resultados tendrían que reducirse a imágenes que tienen las tres etiquetas asociadas.

Entonces, tener una relación N-a-N, ¿cuál es la forma correcta de hacerlo?

Mi enfoque natural estaba generando código de algo como esto, pero desde luego no les gusta a dónde va:

SELECT images.* 
FROM images 
INNER JOIN image_tags ON ... 
INNER JOIN tags ON ... 
WHERE tags.tag = @tag1 
AND EXISTS 
(
    SELECT 1 
    FROM images 
    INNER JOIN image_tags ON ... 
    INNER JOIN tags ON ... 
    WHERE tag = @tag2 
    AND EXISTS 
    (
    SELECT 1 
    FROM images 
    INNER JOIN image_tags ON ... 
    INNER JOIN tags ON ... 
    WHERE tag = @tag3 
    AND EXISTS (...) 
    ... 
) 
) 

Ciertamente, eso no es muy bueno. ¿Alguna idea?

Gracias!

Respuesta

7

Algo así podría funcionar (yo uso id para SELECT y GROUP BY, utilice las columnas que necesita.

SELECT images.id 
FROM images 
INNER JOIN image_tags ON ... 
INNER JOIN tags ON ... 
WHERE tags.tag IN (@tag1, @tag2, @tag3) 
GROUP BY images.id 
HAVING COUNT(*) = @number_of_tags 

Si usted tiene 3 etiquetas como en su ejemplo a continuación number_of_tags tendría que ser 3, y el unirse resultaría en 3 filas por id que coincida.

puede crear esa consulta dinámicamente, o definirlo con, digamos, 10 etiquetas e inicializar con un valor que no se producirá en las etiquetas.

+0

Esto es bastante rígido en cuanto a la cantidad de etiquetas permitidas/requeridas, así como al devolver una fila para cada etiqueta especificada, en lugar de para cada imagen. –

+0

El 'GROUP BY' debe evitar devolver una fila para cada etiqueta. Edité la pregunta para mostrar cómo funcionaría con un número dinámico de etiquetas. –

+0

¡Muchas gracias! No he pensado volver a verificar los resultados con HAVING COUNT(). – Alpha

0

No utilizaría una relación N-N, sino un campo de texto para almacenar las etiquetas.

Esto puede sonar sucio ya que estamos perdiendo la normalidad, pero las etiquetas generalmente se usan solo para buscar texto y el espacio en el disco es barato.

continuación, puede ejecutar

SELECT * FROM images WHERE tags LIKE '%clean%' AND tags LIKE '%dog%'... 
+0

@Peter - Nice alphabetizing ... d viene DESPUÉS de c ... ;-) –

+0

Nota: Su solución haría que el conteo de imágenes por etiqueta y cambiar el nombre o eliminar etiquetas sea más complicado. –

+0

@ md5sum: ¡Dios mío! Lo siento, tuve que eliminar esa publicación ;-) –

0

Usando intersecan usted puede hacer esto:

SELECT images.* 
FROM images 
WHERE image_id IN 
    (
    SELECT image_id FROM image_tags WHERE tag_id = 
     (SELECT tag_id FROM tags WHERE tag = @tag1) 
    INTERSECT 
    SELECT image_id FROM image_tags WHERE tag_id = 
     (SELECT tag_id FROM tags WHERE tag = @tag2) 
    INTERSECT 
     .... 
    ) 

Esto seleccionará todas las imágenes basadas en la intersección (juego) todas las etiquetas en image_tags.

Cuestiones relacionadas