多ON连接
MySql 的连接分为左连接,右连接,内连接,在实际使用时经常使用的是左连接和内连接,即LEFT JOIN 与 JOIN 。基本的操作就不多说了,在看别人的代码或者面试的时候可能会发现一个奇怪的现象,那就是连接后面跟着多个 ON 条件,类似这样
SELECT * FROM A LEFT JOIN B ON A.col1 = B.col1 AND A.col2 = B.col2...
另外,有些人还会把对单表的筛选也放在这里,类似这样
SELECT * FROM A LEFT JOIN B ON A.col1 = B.col1 AND A.col2 = x
这种写法不管是不是故意的,都会正常执行不会报错,但是不是你想要的,就要看情况了
1、内连接
内连接的效果就类似于下面这样,所以连续的ON 条件与 WHERE 后面条件并无差别
SELECT * FROM A,B WHERE A.col = B.col
2、左连接两表字段
SELECT * FROM A LEFT JOIN B ON A.col1 = B.col1 AND A.col2 = B.col2
类似于下面“左连接单表字段” 中的“单表字段在右”,对右表的连接做进一步筛选!
3、左连接单表字段
3.1 单表字段在左
SELECT * FROM A LEFT JOIN B ON A.col1 = B.col1 AND A.col2 = x
这种情况下并不生效,A 左连接 B,那么A 表的行是完全匹配的,那么在左连接中对 A 的筛选都不生效
3.2 单表字段在右
SELECT * FROM A LEFT JOIN B ON A.col1 = B.col1 AND B.col2 = x
这种情况下,在连接过程中,取A表的所有行,然后连接 B表中符合条件的行,即左连接中对 B表的筛选会生效
以上的分析都只是说明两表连接时发生的事,得到的将是一张新表,之后的 where 条件会在此基础上做进一步的筛选!!!
下面是一个实例:现在有一张表question_practice_detail,存储了用户在某天刷题的记录,其中 device_id 表示设备id,可作为用户标识,question_id 表示题目标识,date 标识刷题日期

现在需要计算用户的平均次日留存率,即用户第一天刷题,第二天还来刷题的平均概率是多少?
这题目乍一看挺唬人,次日留存,无非就是连续两天都入库的人,只要拿 连续两天入库的人/总人数 即可。从数据或逻辑上看,存在两个问题:
- 一个人可能在同一天入库多次
- 一个人也可能多次连续入库
对于第1个问题,需要做的就是去重,一个人同一天只能算一次入库。而对于第二个问题,一个人1号2号连续入库,4号5号连续入库,应该算两次入库。所以,去重的不能单纯是用户,而应该是 用户+日期
使用左连接,那么左表中每一组不重复的 用户+日期 都算是一个分母,同理,右表中每一组不重复的 用户+日期 都算是一个分子,实现如下
SELECT count(DISTINCT d2.device_id,d2.date) / count(DISTINCT d1.device_id,d1.date) avg FROM question_practice_detail d1 LEFT JOIN question_practice_detail d2 ON d1.device_id = d2.device_id AND ADDDATE(d1.date, 1) = d2.date
这里必须使用多ON连接,为的是保留全表,同时筛选右表记录,如果用where 那就只能统计连续两天刷题的信息了~
下面附上关联后的结果

结果是 3/10 = 0.3
浙公网安备 33010602011771号