Mysql SQL数据库中N对N关系的搜索
这是我的数据库模型: 我需要的是: 我需要输入几个术语并搜索包含所有这些术语的document.text文档 示例数据: 文件:Mysql SQL数据库中N对N关系的搜索,mysql,Mysql,这是我的数据库模型: 我需要的是: 我需要输入几个术语并搜索包含所有这些术语的document.text文档 示例数据: 文件: SELECT document_iddocument, SUM(IF(term = 'cat', 1, 0)) AS has_0, SUM(IF(term = 'dog', 1, 0)) AS has_1 FROM document_has_term LEFT JOIN term ON (term_idterm = idterm AND
SELECT document_iddocument,
SUM(IF(term = 'cat', 1, 0)) AS has_0,
SUM(IF(term = 'dog', 1, 0)) AS has_1
FROM document_has_term
LEFT JOIN term ON (term_idterm = idterm AND term.term IN
('cat', 'dog'))
GROUP BY document_iddocument;
条款:
例如:
我想搜索包含所有术语的文档:dog cat train。结果将是文件1和文件2,但不是文件3,因为它没有列车,而不是文件4,因为它没有cat或列车
我的第一次尝试是这样的查询:
select document.text from document join document_has_term on
document.iddocument=document_has_term.document_iddocument join term on
term.idterm=document_has_term.term_idterm where term="kindness" and
term="horrible"
SELECT document.* FROM document
WHERE iddocument IN (
SELECT document_iddocument
FROM document_has_term
LEFT JOIN term ON (term_idterm = idterm AND term.term IN
('cat', 'dog') -- list of all terms used
)
GROUP BY document_iddocument
HAVING
(SUM(IF(term = 'cat', 1, 0))!=0) -- for the term "CAT"
AND NOT -- from the "textual query"
(SUM(IF(term = 'dog', 1, 0))!=0) -- for the term "DOG"
);
此查询不选择任何帖子,但它反映了我基本上想要的内容。按您要选择的列分组,只选择那些同时包含这两个术语的帖子
select document.text
from document
join document_has_term on document.iddocument=document_has_term.document_iddocument
join term on term.idterm=document_has_term.term_idterm
where term in ('kindness', 'horrible')
group by document.text
having count(distinct term) = 2
假设每个文档只能有一个术语,如果您运行
SELECT document_iddocument
FROM document_has_term
JOIN term ON (term_idterm = idterm)
WHERE term IN ('cat', 'dog', 'train');
您将有三行,其中三个术语中的每一个都匹配,两行
如果两个术语匹配,依此类推
所以
将仅输出具有三个匹配项的文档ID
此查询在此阶段甚至不需要访问文档
您可以将其用作子选择,以获取其iddocument在此ID列表中的文档:
SELECT document.text FROM document WHERE iddocument IN
( the above select );
更复杂的查询
如果您想运行更复杂的搜索,那么可能应该使用MySQL进行文本搜索并使用全文功能
否则,您需要从外部语言开始构建查询,在外部语言中指定
cat AND NOT dog
这不是SQL,并将其转换为SQL查询
一种有效的方法是尝试通过复杂的查询(比如cat而不是dog)来确定哪一个组件是最有限制的。在本例中,如果您有2000条记录,其中100条记录中有cat,50条记录中有dog,则需要考虑:
-搜索是否存在术语的查询非常有效。
-搜索缺少术语的查询非常昂贵
您将首先运行cat查询,然后删除确实包含dog的项
这种方法也相当复杂
另一种可能性(对于大型数据库不太推荐)是扫描整个文档\u has\u term表并查找所有文档的状态:
SELECT document_iddocument,
SUM(IF(term = 'cat', 1, 0)) AS has_0,
SUM(IF(term = 'dog', 1, 0)) AS has_1
FROM document_has_term
LEFT JOIN term ON (term_idterm = idterm AND term.term IN
('cat', 'dog'))
GROUP BY document_iddocument;
这个查询是用某种外部语言构建的,由三部分组成:模板
变成
(has_0) and not (has_1)
实际上,您可以将其集成到HAVING子句中,并按照如下方式构建查询:
select document.text from document join document_has_term on
document.iddocument=document_has_term.document_iddocument join term on
term.idterm=document_has_term.term_idterm where term="kindness" and
term="horrible"
SELECT document.* FROM document
WHERE iddocument IN (
SELECT document_iddocument
FROM document_has_term
LEFT JOIN term ON (term_idterm = idterm AND term.term IN
('cat', 'dog') -- list of all terms used
)
GROUP BY document_iddocument
HAVING
(SUM(IF(term = 'cat', 1, 0))!=0) -- for the term "CAT"
AND NOT -- from the "textual query"
(SUM(IF(term = 'dog', 1, 0))!=0) -- for the term "DOG"
);
只要在文本查询中使用SQLish语法,如果小心SQL注入。如果您不小心清理您的输入,只允许使用有效的术语和关键字“and”、“or”、“not”和括号,并使用准备好的查询?术语的占位符,很可能是您的…这很有帮助,但是如果我不知道我要搜索多少术语呢?例如,“猫”、“狗”、“火车”中的术语是这样的子选择查询-其中“从术语中选择术语”中的术语是,其中术语=猫,而不是术语=狗这是。。。要复杂得多。为了学习,我尝试了一个简单的解决方案。这很有帮助,但是如果我不知道要搜索多少个术语呢?例如,“cat”、“dog”、“train”中的WHERE term是这样的子选择查询-SELECT term FROM term WHERE term=cat而非term=dog中的WHERE term您正在以某种方式构建查询,并且必须在那里填充WHERE子句。只需确定有多少个术语,并将该数字放入having子句中。
(has_0) and not (has_1)
SELECT document.* FROM document
WHERE iddocument IN (
SELECT document_iddocument
FROM document_has_term
LEFT JOIN term ON (term_idterm = idterm AND term.term IN
('cat', 'dog') -- list of all terms used
)
GROUP BY document_iddocument
HAVING
(SUM(IF(term = 'cat', 1, 0))!=0) -- for the term "CAT"
AND NOT -- from the "textual query"
(SUM(IF(term = 'dog', 1, 0))!=0) -- for the term "DOG"
);