MySQL LEFT JOIN 左表缺失与重复

MySQL 使用LEFT JOIN 后应该得到的结果是左表所有内容,以及匹配到的右表内容(未匹配的留空),但是在实际使用的时候会出现左表内容不全的情况,这是不应该的,出现这种情况的原因可能是筛选条件的位置放错了。

比如现在有两张表:
sell (销售)表:

iddateprofit
00012019-01-013.5
00012019-01-023.5
00022019-01-025
00032019-01-016
00032019-01-033

info(商品信息)表:

idnamesellPrice
0001洗发露7
0002火锅10
0003方便面10

很显然这两张表以id作为键连接在一起

正常的左连表

SELECT sell.id, info.name, 
sell.date, sell.profit FROM sell 
LEFT JOIN info ON info.id=sell.id

这时应该得到正常的结果

idnamedateprofit
0001洗发露2019-01-013.5
0001洗发露2019-01-023.5
0002火锅2019-01-025
0003方便面2019-01-016
0003方便面2019-01-033

这种id多对一的情形一般没有问题,除非你在WHERE条件中对LEFT JOIN的目标表进行了限制,这就是下面的情形

缺失的左表

现在我想看2019-01-01这一天所有商品的利润,无论有没有利润我都想让它显示出来,所以以info表为左表

SELECT info.id, info.name, SUM(sell.profit) AS profit FROM info
LEFT JOIN sell ON sell.id=info.id
WHERE sell.date="2019-01-01"
GROUP BY info.id

这样得出的结果是

idnameprofit
0001洗发露3.5
0003方便面6

0002号商品不见了,因为在筛选条件WHERE sell.date="2019-01-01"中它被筛掉了,出来的结果就不是一张完整的左表。筛选条件的正确位置应该是LEFT JOIN 语句的ON条件或者LEFT JOIN一张临时SELECT出的表,例如
LEFT JOIN sell ON sell.id=info.id AND sell.date="2019-01-01"
或者
LEFT JOIN (SELECT * FROM sell WHERE sell.date="2019-01-01") lt ON lt.id=info.id

多余的左表

上面的缺失情况实际是种id一对多的场景,这种情况下还有可能出现左表行数比原来还要多的情况, 原因是没有进行GROUP BY聚合处理,而一个id匹配到了多个结果都被保留了下来

除此之外还有一种比较坑的情况,发生在存在多个LEFT JOIN的情况,比如在id列上同时LEFT JOIN a表和b表,都是一对多的情况。id=0005的行数匹配到了3个a表中的行和5个b表中的行,那么最后的结果是什么样子呢?如果不做聚合的话,我没记错的话会出现类似笛卡尔积的情况,即使做聚合也是对错误的结果聚合。解决办法是在LEFT JOIN中就提前做好聚合,使得匹配是一对一的。

总结

无论多对一匹配还是一对多匹配都有可能出现因为筛选条件位置不对而引起的缺失,要注意筛选的作用范围(作用于最后结果,还是连接的临时表),以及SQL语句的执行顺序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值