“标记”搜索/排除查询设计问题

时间:2012-04-17 16:16:37

标签: sql photo-tagging

背景:我正在开发一个自制项目,用于管理我自己的图像集合,并且一直在尝试实现基于标记的搜索,以便我可以轻松地筛选它们。

现在,我正在使用RedBean的标记API将标记应用于每个图像的数据库条目,但是我仍然坚持我的实现的具体细节;目前,为了允许搜索多个标签将优化搜索的标签(当搜索“ABC XYZ”时,标记图像必须具有标签“ABC”“XYZ”),

我必须处理服务器端语言中的一些处理而不是SQL,然后运行(可选)第二个查询来验证任何返回的图像没有已明确排除的标记结果。 (搜索“ABC -XYZ”时,标记图像必须包含“ABC”标签和“XYZ”)。

这里的问题是我当前的方法要求我通过服务器端代码运行所有结果,并使任何合理分页/结果偏移的尝试都不准确。

我的目标是只使用一个查询获取包含所请求标记的post表的行(并且不包含任何排除的标记),并且仍然可以使用LIMIT / OFFSET参数来查询获得合理的分页结果。

表模式如下:

Table "post"
Columns:
  id (PRIMARY KEY for post table)
  (image metadata, not relevant to tag search)

Table "tag"
Columns:
  id (PRIMARY KEY for tag table)
  title (string of varying length - assume varchar(255))

Table "post_tag"
Columns:
  id (PRIMARY KEY for post_tag table)
  post_id (associated with column "post.id")
  tag_id (associated with column "tag.id")

如果可能的话,我也希望能够拥有特定于post表格列的WHERE条件。

我应该如何使用查询结构?我一直在玩左连接但是无法获得我需要解决的确切结构。

1 个答案:

答案 0 :(得分:2)

这是基本的想法:

LEFT OUTER JOIN是与您要排除的代码匹配的帖子集。查询中的最后WHERE子句确保这些帖子都不匹配第一个post表中的条目。

INNER JOIN是与所有代码匹配的帖子集。请注意,数字2必须与您在IN子句中提供的唯一标记名称的数量相匹配。

select p.*
from post p
left outer join (
    select pt.post_id    
    from post_tag pt
    inner join tag t on pt.tag_id = t.id
    where t.title in ('UVW', 'XYZ')
) notag on p.id = notag.post_id 
inner join (
    select pt.post_id    
    from post_tag pt
    inner join tag t on pt.tag_id = t.id
    where t.title in ('ABC', 'DEF')
    group by pt.post_id
    having count(distinct t.title) = 2
) yestag on p.id = yestag.post_id 
where notag.post_id is null
--add additional WHERE filters here as needed