2012-04-30 36 views
6

Mam trzy tabele MySQL - zdjęcia, tagi i tagsphotos - i m: n związek między zdjęciami i tagami.Wybieranie zdjęć za pomocą wielu tagów

Photos:  id | filename | ... 
Tags:  id | name 
Tagsphotos: photo | tag 

Chcę zaznaczyć wszystkie zdjęcia z tego warunku:

(tagged as "dirty" AND tagged as "road") AND (tagged as "light.front" OR tagged as "light.side") AND (tagged as "perspective.two-point") 

... co oznacza, że ​​chcę, aby znaleźć wszystkie zdjęcia z brudnej Road, w dwupunktowym perspektywy i albo z boku lub Przednie światła.

Jak mogę to zrobić? Dzięki.

Odpowiedz

3

Chyba będziemy musieli przyłączyć się do stołu do stołu tagów zdjęcia czterokrotnie ... bardzo brzydkie.

SELECT Photos.* 
FROM 
    Photos 
    JOIN (
    Tagsphotos JOIN Tags ON (Tags.id = Tagsphotos.tag) 
) t1 ON (t1.photo = Photos.id) 
    JOIN (
    Tagsphotos JOIN Tags ON (Tags.id = Tagsphotos.tag) 
) t2 ON (t2.photo = Photos.id) 
    JOIN (
    Tagsphotos JOIN Tags ON (Tags.id = Tagsphotos.tag) 
) t3 ON (t3.photo = Photos.id) 
    JOIN (
    Tagsphotos JOIN Tags ON (Tags.id = Tagsphotos.tag) 
) t4 ON (t4.photo = Photos.id) 
WHERE 
     (t1.name = 'dirty' AND t2.name = 'road') 
    AND (t3.name = 'light.front' OR t3.name = 'light.side') 
    AND (t4.name = 'perspective.two-point') 

Podzapytania prawdopodobnie będzie szybciej:

SELECT * 
FROM Photos 
WHERE 
    Photos.id IN (
    SELECT Tagspohotos.photo 
    FROM Tagsphotos JOIN Tags ON (Tags.id = Tagsphotos.tag) 
    WHERE Tags.name = 'dirty' 
) 
    AND Photos.id IN (
    SELECT Tagspohotos.photo 
    FROM Tagsphotos JOIN Tags ON (Tags.id = Tagsphotos.tag) 
    WHERE Tags.name = 'road' 
) 
    AND Photos.id IN (
    SELECT Tagspohotos.photo 
    FROM Tagsphotos JOIN Tags ON (Tags.id = Tagsphotos.tag) 
    WHERE Tags.name = 'light.front' OR Tags.name = 'light.side' 
) 
    AND Photos.id IN (
    SELECT Tagspohotos.photo 
    FROM Tagsphotos JOIN Tags ON (Tags.id = Tagsphotos.tag) 
    WHERE Tags.name = 'perspective.two-point' 
) 
+0

Dzięki. Rozwiązanie z podzapytaniami działa dobrze. –

0

Zakładając zdjęcia i tag kolumny są identyfikatory:

select p.* from Photos p, Tags t, Tagsphotos tp 
where p.id = tp.photo and t.id = tp.tag 
and t.tagged in ("dirty", "road", "perspective.two-point", "light.front") 
group by p.photo 
having count(distinct t.tagged) = 4 

UNION 

select p.* from Photos p, Tags t, Tagsphotos tp 
where p.id = tp.photo and t.id = tp.tag 
and t.tagged in ("dirty", "road", "perspective.two-point", "light.side") 
group by p.photo 
having count(distinct t.tagged) = 4 
+1

'GDZIE t.tagged = x = y I t.tagged '? Jak to kiedykolwiek zwróci wyniki, jeśli 'x <> y'? – eggyal

+1

To był mój pierwszy pomysł i, oczywiście, to nie działa. –

+0

Rzeczywiście! Zmienię to :) –

1

Przepraszamy, nie zdawał sobie sprawy, uzywasz MySQL - zaktualizowaną odpowiedź podanej poniżej.

Zakładając, że każdy tag może być określony tylko jeden raz dla każdego zdjęcia (czyli zdjęcia nie mogą być oznaczone jako „brudne” wiele razy):

SELECT  P.id, 
      P.[filename] 
FROM  Photos P 
INNER JOIN Tagsphotos TP ON TP.photo = P.id 
INNER JOIN Tags T ON TP.tag = T.id 
INNER JOIN (
     SELECT 'dirty' name, 
       10 [weight] 
     UNION 
     SELECT 'road' name, 
       10 [weight] 
     UNION 
     SELECT 'perspective.two-point' name, 
       10 [weight] 
     UNION 
     SELECT 'light.front' name, 
       1 [weight] 
     UNION 
     SELECT 'light.side' name, 
       1 [weight] 
) R ON T.name = R.name 
GROUP BY P.id, 
      P.[filename] 
HAVING SUM(R.[weight]) >= 31 
+0

Zaktualizowano. Usunięto CTE. – weenoid

+0

Uwielbiam to. +1 – eggyal

Powiązane problemy