2

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

现在,我正在使用 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 条件。

我应该使用什么查询结构?我一直在玩左连接,但无法获得解决此问题所需的确切结构。

4

1 回答 1

2

这是基本思想:

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

INNER JOIN是与所有标签匹配的帖子集。请注意,第二个必须与您在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
于 2012-04-17T16:27:36.670 回答