2010-01-04 18 views
6

Mam aplikację internetową, która dopasowuje obrazy do znaczników, i muszę stworzyć sposób dynamicznego zawężania wyników wyszukiwania znaczników. Jednak nie mogę znaleźć prostego sposobu na wykonanie zapytań SQL i właśnie tam potrzebuję twojej pomocy.SQL n-to-n pasujące do wielu wartości

Chodzi o to, że jeśli będę szukał tagów "czysty" i "pies", będę miał wyniki obrazu, które będą miały zarówno znaczniki "czyste" i "pies". Jeśli dodaję również tag "mało", moje wyniki będą musiały zostać zawężone do obrazów, do których przypisano trzy tagi.

A więc, mając relację N do N, co jest właściwym sposobem na zrobienie tego?

Moje naturalne podejście generowania kodu coś takiego, ale na pewno nie podoba dokąd zmierza:

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

Oczywiście, że nie jest naprawdę dobry. Dowolny pomysł?

Dzięki!

Odpowiedz

7

Coś takiego może działać (używam id dla SELECT i GROUP BY użyć kolumny potrzebne.

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 

Jeśli masz 3 znaczniki jak w przykładzie następnie number_of_tags musiałyby być 3, a dołączyć skutkowałoby 3 rzędach za id który pasuje.

można utworzyć tę kwerendę dynamicznie, lub zdefiniować ją, powiedzmy, 10 znaczników i zainicjować ich wartości, która nie będzie występować w tagach.

+0

Jest to dość sztywne pod względem liczby dozwolonych/wymaganych znaczników, a także zwracania wiersza dla każdego określonego znacznika, a nie dla każdego obrazu. –

+0

Funkcja "GROUP BY" powinna unikać zwracania wiersza dla każdego tagu. Edytowałem pytanie, aby pokazać, jak będzie działało z dynamiczną liczbą tagów. –

+0

Wielkie dzięki! Nie pomyślałem o ponownym sprawdzeniu wyników za pomocą HAVING COUNT(). – Alpha

0

Nie używałbym relacji N-N, ale pole tekstowe do przechowywania tagów.

Może to zabrzmieć nieprzyjemnie, ponieważ tracimy normalność, ale tagi są zwykle używane do wyszukiwania tekstu, a miejsce na dysku jest tanie.

Następnie można uruchomić

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

@Peter - Ładne alfabetyczne ... d przychodzi PO C ... ;-) –

+0

Uwaga: Twoje rozwiązanie sprawi, że zliczanie obrazów na tag i zmiana nazwy lub usuwanie tagów będzie bardziej skomplikowana. –

+0

@ md5sum: OMG! Przepraszamy, musiałem usunąć ten wpis ;-) –

0

Korzystanie przecinają można to zrobić:

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

Spowoduje to zaznaczenie wszystkich obrazów opartych na skrzyżowaniu (pasująca do wszystkich) Tagi w image_tags.

Powiązane problemy