2012-04-30 103 views
6

我有三张MySQL表格 - 照片,标签和tagsphotos - 以及照片和标签之间的m:n关系。通过多个标签选择照片

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

我想选择与此条件的所有照片:

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

...这意味着我要找到肮脏的道路的所有照片,在两点透视,要么与侧或前灯。

我该怎么办?谢谢。

回答

3

我认为你将不得不加入标签表,照片表四次......很丑陋。

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

子查询可能会更快: - 在下面给出的答案更新

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

谢谢。子查询解决方案运行良好。 –

0

假设照片和标签列的ID:

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

'WHERE t.tagged = x和t.tagged = Y '?如果'x <> y'会如何返回结果? – eggyal

+1

这是我的第一个想法,当然,它不起作用。 –

+0

确实!我会改变:) –

1

道歉,我没你使用MySQL实现。

假设每个标签只能使用一次为每个指定的相片(即相片不能被标记为“脏”多次):

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

已更新。删除了CTE。 – weenoid

+0

我很喜欢这个。 +1 – eggyal