关于left join的一些事 ## 先做个题吧 我们先建两个表吧。一个叫classes,一个叫students。 ```sql 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'); ``` 现在有两个需求: 1. 找出每个班级的名称及其对应的女同学数量 2. 找出一班的同学总数 第一题正确答案是: ```sql 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 ``` 第二题正确答案是: ```sql 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后面的条件来筛选临时表中的数据,最后返回。下面用伪代码表示一下 ```java 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后面。