我正在为我的练习编写一个小型搜索引擎。我想在其中添加搜索功能。我想在匹配标题,描述和关键字时选择questions
表的所有行。
我创建了以下3个表:
questions(id(PK), title, description)
keywords(id(PK), label);
questions_keywords(id(PK), question_id(FK), keyword_id(FK));
到目前为止,我的SQL查询如下所示:
SELECT q.* FROM question_keywords qk
JOIN keywords k ON qk.keyword_id=k.id
JOIN questions q ON qk.question_id=q.id
WHERE q.description LIKE '%javascript%'
OR
k.keyword_label LIKE '%java%'
在此查询中,我选择questions
表中包含子字符串java
或javascript
我做得对吗还是有更好的方法吗?
提前致谢。
答案 0 :(得分:0)
如其他人所说,我会加上不同的。我也会重新排序表格。从功能上来说,我不认为这只会让我感到烦恼......哈哈
SELECT DISTINCT
q.*
FROM
questions AS q
JOIN
question_keywords AS qk ON q.id = qk.question_id
JOIN
keywords AS k ON qk.keyword_id = k.id
WHERE
q.description LIKE '%javascript%'
OR
k.label LIKE '%java%';
正如你在这个DBfiddle中看到的那样
https://www.db-fiddle.com/f/pcVqcMm1yUoU6NdSHitCVr/2
您获得重复的原因基本上称为笛卡尔积
https://en.wikipedia.org/wiki/Cartesian_product
简单来说,就是拥有“多对多”的结果。关系。
如果你在小提琴中看到我故意通过我在最后2个插入中添加到Bridge(或Junction)表question_keywords
的内容创建了这种情况
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,2);
重复行,只是因为此表中有2
个条目,4
的匹配值为question_id
。所以这些只是Duplicates
,因为我们只选择questions
表中的字段。如果我们包含关键字表中的字段。然后,一行会有一个关键字或Java #1
,而另一行会有Javascript #2
作为关键字。
希望有助于解释它。
其他一些注意事项:
根据问题中的表格定义,您在k.keyword_label LIKE '%java%'
发布的查询中的语法错误应为k.label LIKE '%java%'
。
通常,Junction表应该是它加入的两个表的组合(你几乎已经这样做了)但复数错误question_keywords
应该是questions_keywords
它是一个很小的东西,但是在编写查询时可能会造成混淆。
对于Junction表,实际上不需要单独的主键。
如果您注意到我是如何在小提琴中创建表格的。
CREATE TABLE question_keywords(
question_id INT(10) UNSIGNED NOT NULL,
keyword_id INT(10) UNSIGNED NOT NULL,
PRIMARY KEY(question_id,keyword_id)
);
主键是2个外键的复合。这具有防止发生真正重复行的额外好处。例如,如果你试过这个
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);
通过我的设置,将无法创建副本。您仍然可以拥有单独的主键(代理键),但您应该在这两个键上创建复合唯一索引来代替它。