多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. 一个人可能在同一天入库多次
  2. 一个人也可能多次连续入库

  对于第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

  

 

posted @ 2022-04-20 11:22  远走不高飞  阅读(261)  评论(0)    收藏  举报