2010-01-04 2 views
6

У меня есть веб-приложение, которое соответствует изображениям для тегов, и мне нужно создать способ динамического уточнения результатов поиска тегов. Тем не менее, я не могу найти чистый способ сделать эти SQL-запросы, и именно там мне нужна ваша помощь.SQL n-to-n, соответствующий нескольким значениям

Идея состоит в том, что если я ищу теги «clean» и «dog», у меня будут результаты изображения, в которых есть как теги «clean», так и «dog». Если я также добавлю тег «little», мои результаты должны были бы сужаться к изображениям, связанным с тремя тегами.

Итак, имея отношение N-to-N, что является правильным способом сделать это?

Мой естественный подход генерации кода что-то вроде этого, но я, конечно, не нравится, где это происходит:

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 (...) 
    ... 
) 
) 

Конечно, это не очень хорошо. Есть идеи?

Спасибо!

ответ

7

Что-то подобное может работать (я использую id для SELECT и GROUP BY используйте столбцы вам нужно.

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 

Если у вас есть 3 тегов, как в вашем примере, то number_of_tags должно быть 3, и присоединиться приведет в 3 ряда на id, что соответствует.

Вы можете создать этот запрос динамически, или определить его, скажем, 10 тегов и инициализировать их со значением, которое не будет иметь место в тегах.

+0

Это довольно жесткое количество разрешенных/требуемых тегов, а также возвращающая строку для каждого указанного тега, а не для каждого изображения. –

+0

'GROUP BY' следует избегать возврата строки для каждого тега. Я редактировал вопрос, чтобы показать, как он будет работать с динамическим числом тегов. –

+0

Спасибо большое! Я не думал о повторной проверке результатов с помощью HAVING COUNT(). – Alpha

0

Я бы не использовал отношение N-N, а текстовое поле для хранения тегов.

Это может звучать грязно, поскольку мы теряем нормальность, но теги обычно используются для текстового поиска, и в любом случае дисковое пространство дешево.

Вы можете запустить

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

@Peter - Nice alphabetizing ... d приходит ПОСЛЕ c ... ;-) –

+0

Примечание. Ваше решение будет делать подсчет изображений для каждого тега и переименование или удаление тегов более сложным. –

+0

@ md5sum: OMG! Извините, мне пришлось удалить этот пост ;-) –

0

Использование пересекаются вы могли бы сделать это:

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 
     .... 
    ) 

Это позволит выбрать все изображения на основе пересечения (сопоставления всех) тегов в image_tags.

Смежные вопросы