关于left join的一些事
先做个题吧
我们先建两个表吧。一个叫classes,一个叫students。
DROP TABLE IF EXISTS `classes`;
CREATE TABLE `classes` (
`id` int(11) NOT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `classes` VALUES (1, '一班');
INSERT INTO `classes` VALUES (2, '二班');
INSERT INTO `classes` VALUES (3, '三班');
CREATE TABLE `students` (
`id` int(11) NOT NULL,
`class_id` int(11) NULL DEFAULT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gender` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `students` VALUES (1, 1, '小明', 'M');
INSERT INTO `students` VALUES (2, 1, '小红', 'F');
INSERT INTO `students` VALUES (3, 1, '小军 ', 'M');
INSERT INTO `students` VALUES (4, 1, '小米', 'F');
INSERT INTO `students` VALUES (5, 2, '小白', 'F');
INSERT INTO `students` VALUES (6, 2, '小兵', 'M');
INSERT INTO `students` VALUES (7, 2, '小林', 'M');
INSERT INTO `students` VALUES (8, 3, '小新', 'F');
INSERT INTO `students` VALUES (9, 3, '小王', 'M');
INSERT INTO `students` VALUES (10, 3, '小丽', 'F');
现在有两个需求:
- 找出每个班级的名称及其对应的女同学数量
- 找出一班的同学总数
第一题正确答案是:
SELECT c.name, count(s.name) as num
FROM classes c left join students s
on s.class_id = c.id
and s.gender = 'F'
group by c.name
第二题正确答案是:
SELECT c.name, count(s.name) as num
FROM classes c left join students s
on s.class_id = c.id
where c.name = '一班'
group by c.name
你写对了吗?我们注意到,第一个过滤条件是放在on后面,第二个是放在where后面,为什么呢?
left join的本质
left join 就是以左表为基准,遍历每一行,然后根据on后面的条件,去匹配右表的数据,有几行就加几行,一行都没有,就只放一个左表的数据,右表值为空。这样就生成了一张临时表数据,然后再通过where后面的条件来筛选临时表中的数据,最后返回。下面用伪代码表示一下
for (int i = 0 ; i < classes.size(); ++i){
int b = false;
for(int j= 0; j < students.size(); ++j){
//处理on后面的条件
if(classes[i].id = students.[j].id ){
//往temp放一条数据
temp.add();
//处理过了,就后面就不放空数据了
b = true;
}
}
//如果一条数据都没匹配上,就放一条以左表为基准的空数据
if(!b){
temp.add();
}
}
上面就是生成临时表,然后再根据where条件过滤数据。
由此我们可知,如果当左表数据的某个字段有严格限制时,就放在where后面,否则就放在on后面。比如说我们要查所有班级的女同学的数据,那么我们的重点是班级,女同学这个点是有可能为0的,所以放在on后面。