2

我不是数据库程序员,但我有一个简单的数据库支持的应用程序,其中有带有标签的项目。每个项目可能有多个标签,所以我使用一个典型的联结表(像这样),其中每一行表示具有适当 ID 的项目具有具有适当 ID 的标签的事实。

当我想做一些事情,比如选择具有给定标签的所有项目时,这非常合乎逻辑。

但是,进行搜索的典型模式是什么AND也就是说,如果我想找到所有具有某组标签的所有项目怎么办?这是一个如此常见的操作,我认为一些介绍教程会涵盖它,但我想我没有找对地方。

我尝试的方法是INTERSECT首先直接使用,然后使用子查询和IN. 这很有效,但在我添加搜索词时会快速构建看起来很长的查询。而且,至关重要的是,这种方法似乎比将所有标签作为文本推入一个“标签”列并使用 SQLite 的全文搜索的方法慢一个数量级。(而且,正如我所期望/希望的那样,当我添加更多术语时,FTS 搜索会变得更快,而 INTERSECTS 方法似乎并非如此。)

什么是正确的设计模式,什么是让它变得活泼的正确方法?在这种情况下,我使用的是 SQLite,但我最感兴趣的是一个一般性的答案,因为这一定是一件很常见的事情。

4

2 回答 2

2

以下是标准的 ANSI SQL 解决方案,它避免同步 id 的数量和 id 本身。

with tag_ids (tid) as (
   values (1), (2)
)
select id
from tags
where id (select tid from tag_ids)
having count(*) = (select count(*) from tag_ids);

valuesPostgreSQL 和 DB2 支持子句(“行构造函数”)。对于不支持该功能的数据库,您可以将其替换为简单的“选择”,例如在 Oracle 中,这将是:

with tag_ids (tid) as (
   select 1 as tid from dual
   union all 
   select 2 from dual
)
select id
from tags
where id (select tid from tag_ids)
having count(*) = (select count(*) from tag_ids);

对于 SQL Server,您只需省略“from dual”,因为它不需要 aFROM子句SELECT

这假设一个标签只能被分配一次。如果不是这种情况,则需要count(distinct id)having子句中使用 a。

于 2012-08-20T21:33:38.127 回答
1

我倾向于通过以下方式使用组:

select id
from tags
where id in (<tag1>, <tag2>)
group by id
having count(*) = 2

这将保证两者都出现。

对于无限大小的列表,您可以将 id 存储在字符串中,例如 '|tag1|tag2|tag3|' (注意结束处的分隔符)。然后你可以这样做:

select id
from tags
where @taglist like '%|'+tag+'|%'
group by id
having count(*) = len(@taglist) - (len(replace(@taglist, '|', '') - 1)

这是使用 SQL Server 语法。但是,它说的是两件事。WHERE 子句表示标签在列表中。HAVING 子句表示匹配的数量等于列表的长度。它通过计算分隔符的数量并减去 1 来实现这一点。

于 2012-08-20T18:57:24.230 回答