2012-04-30 33 views
6

Tôi có ba bảng MySQL - ảnh, thẻ và hình ảnh thẻ - và mối quan hệ m: n giữa ảnh và thẻ.Chọn ảnh theo nhiều thẻ

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

Tôi muốn chọn tất cả ảnh với tình trạng này:

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

... có nghĩa là tôi muốn tìm tất cả các hình ảnh với đường bẩn, trong quan điểm hai điểm và một trong hai bên hoặc với đèn trước.

Tôi có thể làm như thế nào? Cảm ơn.

Trả lời

3

Tôi nghĩ rằng bạn sẽ phải tham gia bảng thẻ vào ảnh bảng gấp bốn lần ... khá xấu xí.

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

các truy vấn con có lẽ sẽ nhanh hơn:

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

Cảm ơn. Giải pháp với các truy vấn con hoạt động tốt. –

0

Giả sử cột ảnh và thẻ là 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

'Ở ĐÂU t.tagged = x VÀ t.tagged = y '? Làm thế nào mà sẽ bao giờ trở lại một kết quả nếu 'x <> y'? – eggyal

+1

Đây là ý tưởng đầu tiên của tôi và tất nhiên, nó không hoạt động. –

+0

Thật vậy! Tôi sẽ thay đổi nó :) –

1

Xin lỗi, tôi đã không nhận ra bạn đang sử dụng MySQL - Câu trả lời được cập nhật đưa ra dưới đây.

Giả sử rằng mỗi thẻ chỉ có thể được xác định một lần cho mỗi bức ảnh (ví dụ một bức ảnh không thể được gắn thẻ như 'bẩn' nhiều lần):

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

Đã cập nhật. Đã xóa CTE. – weenoid

+0

Tôi yêu thích điều này. +1 – eggyal

Các vấn đề liên quan