一、MySQL内关联(自关联)
当有这样的需求,对同一张表进行不同条件连续查询时(例如不同条件的group by),需要用到INNER JOIN内连接,也就是自关联。
举例说明,例如有下面这两张表,一张试题表,一张分类表(为简单理解,每个表只有两三个字段)
试题表:
create table question(
id int primary key auto_increment, /*主键*/
name varchar(255) NOT NULL, /*试题名称*/
difficult varchar(64) NOT NULL, /*题难度*/
class_id int NOT NULL /*分类id*/
);
分类表:
create table class(
id int primary key auto_increment, /*分类id 主键*/
title varchar(255) NOT NULL /*分类名称*/
attribute varchar(128) NOT NULL /*属性*/
);
试题表插入数据:
insert into question(name,difficult,class_id) values('这是一道题','3','1001');
insert into question(name,difficult,class_id) values('这是一道题','3','1002');
分类表插入数据:
insert into class(id,title,attribute) values(1001,'数学题','中学奥数题型');
insert into class(id,title,attribute) values(1002,'逻辑题','思维培养题型');
现在需要根据试题分类id,查询同名称题所属所有分类的名称(注释:可能有相同名称的题,归属不用的分类),已知条件只有一个题分类class_id = '1001'
传统最简单的方法是,查询两次数据库,第一次通过题id查出题名称,第二次通过题名称查出所有id,并关联分类表查出分类名称。
1、SELECT NAME FROM question WHERE class_id = '1001';
2、SELECT cs.title FROM question qs LEFT JOIN class cs ON qs.class_id = cs.id WHERE qs.name = '上条语句查询的name';
上文做法做通俗易懂,但是会增加一次数据库的连接,同时增加逻辑处理代码,若要用一条SQL语句查询出结果,INNER JOIN自关联为最佳,如下语句:
SELECT question_1st.name,class.title FROM question question_1st INNER JOIN (SELECT NAME FROM question WHERE class_id = 1001) question_2nd ON question_1st.name = question_2nd.name LEFT JOIN class class ON question_1st.class_id = class.id;
二、MySQL左右关联
我们最常使用的左关联,就是两张表通过LEFT JOIN连接起来,后面带有WHERE条件,如此一来SQL语句即完成,这种SQL简单写法初学者就可以轻松搞定。
举例说明:比如上面两张表,已知题的名称“这是一道题”和分类名称“数学题”,根据这两个条件查询题的难度和分类属性。
大部分人可能会这样写SQL语句:
select qs.*,cs.title from question qs left join class cs on qs.class_id = cs.id where qs.name = "这是一道题" and cs.title = "数学题";
这种语句在理想状态下是没问题的,为什么说是理想状态,就是指两张表中的数据皆满足WHERE后面的条件。
但若是WHERE中的个条件在其中一张数据表中没有(不满足),那后面查询到的结果便是空,这样做在实际应用中便埋下隐患。
假设题的名称不变,分类名称变为“英语题”,这个分类在上面添加数据时是没有的,我们来实际试一下。
select * from question qs left join class cs on qs.class_id = cs.id where qs.name = "这是一道题" and cs.title = "英语题";
怎样解决,在连表查询时换一种写法就可以巧妙避免BUG的发生,仔细读下面的SQL语句
select qs.*,cs.title from question qs left join (select * from class where title = "数学题") cs on qs.class_id = cs.id where qs.name = "这是一道题";
注:因为要查询的题难度在question表中,我们首先查询了question表,所以实用left join,查出的数据是左表的全部,右表没有的数据显示NULL值。反之则用right join进行关联查询。