2010-01-04 30 views
6

Tôi đã có ứng dụng web khớp với hình ảnh vào thẻ và tôi cần tạo cách tinh chỉnh kết quả cho tìm kiếm thẻ. Tuy nhiên, tôi không thể tìm thấy một cách rõ ràng để thực hiện các truy vấn SQL đó, và đó là nơi tôi cần sự giúp đỡ của bạn.SQL n-to-n khớp nhiều giá trị

Ý tưởng là nếu tôi tìm kiếm thẻ "sạch" và "chó", tôi sẽ có kết quả hình ảnh có cả thẻ "sạch" và "chó". Nếu tôi cũng bao gồm thẻ "nhỏ", kết quả của tôi sẽ phải thu hẹp hình ảnh có ba thẻ được liên kết.

Vì vậy, có mối quan hệ N-to-N, đó là cách chính xác để làm điều này?

phương pháp tự nhiên của tôi đã tạo mã một cái gì đó như thế này, nhưng tôi chắc chắn không thích nơi nó đang xảy ra:

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

Chắc chắn, đó không phải là thực sự tốt. Bất kỳ ý tưởng?

Cảm ơn!

Trả lời

7

Something như thế có thể làm việc (tôi sử dụng id cho SELECTGROUP BY, sử dụng các cột mà bạn cần.

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 

Nếu bạn có 3 thẻ như trong ví dụ của bạn thì number_of_tags sẽ phải là 3, và tham gia sẽ cho kết quả trong vòng 3 hàng mỗi id phù hợp.

Bạn có thể tạo truy vấn động, hoặc định nghĩa nó với, nói, 10 thẻ và khởi tạo chúng với giá trị đó sẽ không xảy ra trong các thẻ.

+0

Điều này khá cứng nhắc về số lượng thẻ được cho phép/bắt buộc, cũng như trả về một hàng cho mỗi thẻ được chỉ định, thay vì cho mỗi hình ảnh. –

+0

'GROUP BY' nên tránh trả lại hàng cho mỗi thẻ. Tôi đã chỉnh sửa câu hỏi để hiển thị câu hỏi sẽ hoạt động như thế nào với một số lượng thẻ động. –

+0

Cảm ơn rất nhiều! Tôi đã không nghĩ đến việc kiểm tra lại kết quả với HAVING COUNT(). – Alpha

0

Tôi sẽ không sử dụng mối quan hệ N-N nhưng một trường văn bản để lưu trữ các thẻ.

Điều này nghe có vẻ bẩn vì chúng tôi mất tiêu chuẩn nhưng các thẻ thường chỉ được sử dụng cho tìm kiếm văn bản và dung lượng ổ đĩa rẻ.

Sau đó bạn có thể chạy

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

@Peter - Đẹp bảng chữ cái ... d đến SAU c ... ;-) –

+0

Lưu ý: Giải pháp của bạn sẽ làm cho việc đếm hình ảnh trên mỗi thẻ và đổi tên hoặc xóa thẻ phức tạp hơn. –

+0

@ md5sum: OMG! Rất tiếc, tôi phải xóa bài đăng đó ;-) –

0

Sử dụng giao nhau bạn có thể làm điều này:

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

này sẽ chọn tất cả các hình ảnh dựa trên các ngã tư (phù hợp với tất cả) thẻ trong image_tags.

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