背景:我正在开发一个自制项目,用于管理我自己的图像集合,并且一直在尝试实现基于标记的搜索,以便我可以轻松地筛选它们。
现在,我正在使用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条件。
我应该如何使用查询结构?我一直在玩左连接但是无法获得我需要解决的确切结构。
答案 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