2010-01-04 66 views
6

我有一个将图像与标签匹配的Web应用程序,我需要创建一种动态优化标签搜索结果的方式。但是,我无法找到一个干净的方式来进行SQL查询,而这正是我需要您的帮助的地方。SQL n对n匹配多个值

这个想法是,如果我搜索标签“干净”和“狗”,我将有图像结果,同时具有标签“干净”和“狗”。如果我还包含“小”标签,我的结果将不得不缩小到具有三个标签关联的图像。

因此,有一个N对N的关系,这是做到这一点的正确方法?

我自然的方法是生成代码这样的事情,但我肯定不喜欢往哪里去:

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

当然,这不是真的很好。任何想法?

谢谢!

回答

7

类似的东西可以工作(我用idSELECTGROUP BY,使用你所需要的列。

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 

如果你有3个标签,如在你的榜样,然后number_of_tags必须是3,加入将导致3行每id匹配。

您可以动态地创建查询,或者,比如说定义它,10个标签,并不会在标签出现的值初始化。

+0

这对于允许/需要的标签数量非常严格,并且对每个指定的标签而不是每个图像都返回一行。 – 2010-01-04 17:02:05

+0

'GROUP BY'应该避免为每个标签返回一行。我编辑了这个问题,以显示它如何与动态数量的标签一起工作。 – 2010-01-04 17:17:45

+0

非常感谢!我没有想过用HAVING COUNT()重新检查结果。 – Alpha 2010-01-05 14:11:56

0

我不会使用N-N关系,而是使用文本字段来存储标签。

这听起来很肮脏,因为我们失去了常态,但标签通常只用于文本搜索,而且磁盘空间很便宜。

然后,您可以运行

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

@Peter - 尼斯字母排序... d在c后面出现... ;-) – 2010-01-04 16:52:33

+0

注意:您的解决方案会为每个标签计数图像,重命名或删除标签更复杂。 – 2010-01-04 16:53:43

+0

@ md5sum:OMG!对不起,我不得不删除那个帖子;-) – 2010-01-04 16:54:35

0

使用相交,你可以这样做:

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

这将选择基于交点(匹配所有)在image_tags标签的所有图像。