我不是数据库程序员,但我有一个简单的数据库支持的应用程序,其中我有带标签的项目。每个项目可能有多个标签,因此我使用的是典型的联结表(如this),其中每一行代表具有相应ID的项目具有适当ID的标签。
当我想要选择具有给定标签的所有项目时,这非常合乎逻辑。
但是,进行AND
次搜索的典型模式是什么?也就是说,如果我想找到所有具有所有特定标签集的项目,该怎么办?这是一个常见的操作,我认为一些介绍教程会覆盖它,但我想我不是在寻找合适的地方。
我尝试的方法是首先使用INTERSECT
,然后使用子查询和IN
。这有效,但在我添加搜索词时会快速构建看似很久的查询。而且,至关重要的是,这种方法似乎比将所有标签作为文本推入一个“标签”列并使用SQLite的全文搜索方法慢一个数量级。 (并且,正如我所期望/希望的那样,当我添加更多术语时,FTS搜索变得更快,而INTERSECTS方法似乎并非如此。)
这里适当的设计模式是什么,以及使它变得活泼的正确方法是什么?我在这种情况下使用SQLite,但我对一般答案最感兴趣,因为必须是常见的事情。
答案 0 :(得分: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);
PostgreSQL和DB2支持values
子句(“行构造函数”)。对于不支持该数据库的数据库,您可以使用简单的“选择”替换它,例如在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”,因为它不需要FROM
的{{1}}子句。
这假定一个标签只能分配一次。如果不是这种情况,则需要在SELECT
子句中使用count(distinct id)
。
答案 1 :(得分: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子句表示匹配数等于列表的长度。通过计算separtors的数量并减去1来实现这一点。