按多个标签选择照片

时间:2012-04-30 12:29:17

标签: mysql sql

我有三张MySQL表 - 照片,标签和标签照片 - 以及照片和标签之间的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 个答案:

答案 0 :(得分: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'
  )

答案 1 :(得分: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

答案 2 :(得分: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