目前我有以下表格结构。
主表文档:
ID | 文件名 |
---|---|
1 | document1.pdf |
2 | document2.pdf |
3 | document3.pdf |
明细表关键字:
ID | 文档ID | 关键字 |
---|---|---|
1 | 1 | 关键字A |
2 | 1 | 关键字B |
3 | 1 | 关键字C |
4 | 2 | 关键字B |
5 | 3 | 关键字A |
6 | 3 | 关键字D |
创建此代码的代码:
CREATE TABLE Documents (
ID int IDENTITY(1,1) PRIMARY KEY,
Filename nvarchar(255) NOT NULL
);
CREATE TABLE Keywords (
ID int IDENTITY(1,1) PRIMARY KEY,
DocumentID int NOT NULL,
Keyword nvarchar(255) NOT NULL
);
INSERT INTO Documents(Filename) VALUES
('document1.pdf'), ('document2.pdf'), ('document3.pdf');
INSERT INTO Keywords(DocumentID, Keyword) VALUES
(1, 'KeywordA'),
(1, 'KeywordB'),
(1, 'KeywordC'),
(2, 'KeywordB'),
(3, 'KeywordA'),
(3, 'KeywordD');
我正在寻找一种方法来获取与某个关键字匹配的所有文档。
这可能是例如使用以下 T-SQL 查询编写:
SELECT Documents.*
FROM Documents
WHERE Documents.ID IN
(
SELECT Keywords.DocumentID
FROM Keywords
WHERE Keywords.Keyword = 'KeywordA'
)
这成功了。
我目前遇到的问题是,我想查找与多个关键字匹配的所有文档,并结合逻辑 AND。
例如查找包含三个详细记录的文档,关键字为 A、B 和 C。
我认为以下可能有效,但我根本不知道这是否高效或优雅:
SELECT Documents.*
FROM Documents
WHERE Documents.ID IN
(
SELECT Keywords.DocumentID
FROM Keywords
WHERE
Keywords.Keyword = 'KeywordA' OR
Keywords.Keyword = 'KeywordB'
GROUP BY Keywords.DocumentID HAVING COUNT(*) = 2
)
如何编写(高性能)SQL 查询来查找所有关联多个关键字的文档。
如果更简单,一个具有恒定关键字数量(例如 3 个)的解决方案就足够了。
答案 0 :(得分:1)
希望以下查询对您有帮助
SELECT D.ID
FROM Documents D
JOIN Keywords K ON K.DocumentID = D.ID
WHERE K.Keyword IN ('KeywordA', 'KeywordB', 'KeywordC')
GROUP BY D.ID
HAVING COUNT(DISTINCT K.Keyword) = 3
答案 1 :(得分:1)
您尝试使用的技术称为 Relational Division With Remainder,换句话说:查找包含一组特定行的所有组。
您当前的查询是执行此操作的标准方法之一,还有其他方法。
如果您在表变量或 TVP 中有关键字,...
DECLARE @keywords AS TABLE (Keyword varchar(50));
INSERT @keywords VALUES
('KeywordA'), ('KeywordB'), ('KeywordC');
...您可以使用以下内容使其更整洁:
SELECT d.*
FROM Documents d
WHERE d.ID IN
(
SELECT k.DocumentID
FROM Keywords k
JOIN @keywords kt ON kt.Keyword = k.Keyword
GROUP BY k.DocumentID
HAVING COUNT(*) = (SELECT COUNT(*) FROM @keywords)
);
另一种选择:
SELECT d.*
FROM Documents d
WHERE EXISTS (SELECT 1
FROM @keywords kt
LEFT JOIN Keywords k ON kt.Keyword = k.Keyword
AND k.DocumentID = d.ID
HAVING COUNT(*) = COUNT(k.keywords) -- there are no missing matches
);
另一个,有点令人困惑:
SELECT d.*
FROM Documents d
WHERE NOT EXISTS (SELECT 1
FROM @keywords kt
WHERE NOT EXISTS (SELECT 1
FROM Keywords k
WHERE k.Keyword = kt.Keyword
AND K.DocumentID = d.ID
)
);
-- For each document, there are no keywords for which there is no match