sql - 具有逻辑操作的高性能 SQL 标签搜索查询
问题描述
如何在 SQL 中实现布尔标记搜索?
这个问题与我能找到的差不多,但有几个。
我知道的唯一真正的解决方案是通过后端代码生成这样的查询并将其放入 SQL 中,但我想它很慢,我也想知道是否有其他方法可以做到这一点(比如有一个主查询而不是多个)。
还有可能使用的解决方案IN
或类似的解决方案:
如何在 SQL 中基于多个“标签”查询数据?
我不能使用典型的GROUP BY HAVING COUNT
解决方案,因为它不能在具有标签列表的上下文中操作,正如该用户指出的那样: Implementing a tag search with operands
我应该指定大多数现有解决方案都不起作用,因为我正在寻找能够进行更复杂查询的东西,例如括号分组和嵌套操作数。
模式是“毒药” http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/
SELECT id AS post_id
FROM posts
WHERE EXISTS (SELECT name FROM tags WHERE post IS post_id AND name IS 'random')
AND NOT (
EXISTS (SELECT name FROM tags WHERE post IS post_id AND name IS 'query') AND
EXISTS (SELECT name FROM tags WHERE post IS post_id AND name IS '1')
)
AND EXISTS (SELECT name FROM tags WHERE post IS post_id AND name IS '2')
AND EXISTS (SELECT name FROM tags WHERE post IS post_id AND name IS '3')
AND EXISTS (SELECT name FROM tags WHERE post IS post_id AND name IS 'racecar')
解决方案
AGROUP BY HAVING COUNT
会起作用——而且速度很快,而且用途广泛。一些例子:
CREATE TABLE tags(
post_id INT,
name VARCHAR(50),
UNIQUE KEY (post_id, name)
);
INSERT INTO tags(post_id, name) VALUES
(1, 'foo'),
(1, 'bar'),
(2, 'foo'),
(3, 'bar'),
(4, 'baz'),
(5, 'foo'),
(5, 'bar'),
(5, 'meh');
-- posts tagged foo AND bar
-- returns 1, 5
SELECT post_id
FROM tags
GROUP BY post_id
HAVING COUNT(CASE WHEN name IN ('foo', 'bar') THEN 1 END) = 2;
-- posts tagged foo OR bar
-- returns 1, 2, 3, 5
SELECT post_id
FROM tags
GROUP BY post_id
HAVING COUNT(CASE WHEN name IN ('foo', 'bar') THEN 1 END) > 0;
-- posts tagged (foo AND bar) OR (baz)
-- returns 1, 4, 5
SELECT post_id
FROM tags
GROUP BY post_id
HAVING COUNT(CASE WHEN name IN ('foo', 'bar') THEN 1 END) = 2
OR COUNT(CASE WHEN name IN ('baz') THEN 1 END) = 1;
-- posts tagged (foo AND bar) AND (no other tags)
-- returns 1
SELECT post_id
FROM tags
GROUP BY post_id
HAVING COUNT(CASE WHEN name IN ('foo', 'bar') THEN 1 END) = 2
AND COUNT(*) = 2;
-- posts tagged (foo OR bar) AND NOT (meh)
-- returns 1, 2, 3
SELECT post_id
FROM tags
GROUP BY post_id
HAVING COUNT(CASE WHEN name IN ('foo', 'bar') THEN 1 END) > 0
AND COUNT(CASE WHEN name IN ('meh') THEN 1 END) = 0;
我的答案没有涵盖将表达式转换为tag1 AND tag2 OR tag3
相应的表达式,HAVING COUNT
但五个示例应该就足够了。
推荐阅读
- python - 烧瓶将 request.form 值传递给 url_for
- javascript - 如何在布局内容或视图中调用 javascript 函数
- json - 使用 net/http 在 PUT "Body length 0" 上出现错误
- git - Git推送奇怪的行为
- azure-devops - 用户界面更改现在我不知道如何找到我的东西
- jquery - 使用while循环从数据库中获取数据并插入到php和mysql中的另一个表中
- html - 在 macOS 的 Safari 上删除正文中行右侧不需要的白色填充
- javascript - 下载文件“发送带有下载名称的文件”
- reactjs - ReactJs 中单一事实来源的实现
- jenkins - 你如何强迫 Jenkins(通过 Blue Ocean)从 GitHub 中提取?