LEFT JOIN返回结果与INNER JOIN一致,存入视图却正常,原因何在?
嘿,咱们来好好捋捋你遇到的这个SQL问题:你本来想用LEFT JOIN找出A表中在B表里没匹配的行,结果查询结果却和INNER JOIN一模一样,存入视图后反而正常了——这背后其实是LEFT JOIN的逻辑细节没搞对。
为啥原查询会变成INNER JOIN的效果?
说白了,问题出在WHERE子句里的B表字段过滤条件。当你用LEFT JOIN时,A表的所有行都会被保留下来,那些在B表里找不到匹配的A行,对应的B表字段全是NULL。但你加了date(b.trt_date) = '2017-11-18'这个条件,对于B表字段为NULL的那些行来说,date(NULL)还是NULL,而NULL和任何值做比较的结果都是不成立的,WHERE子句直接把这些行给过滤掉了。最后剩下的就只有A和B能匹配上,且B表日期符合条件的行,这不就和INNER JOIN的结果完全一样了嘛!
正确的查询写法应该是这样
要实现“找出A表中与B表无匹配的行,同时如果有匹配的话只关联B表中日期符合条件的行”,你得把B表的过滤条件放到LEFT JOIN的ON子句里,而不是WHERE里:
SELECT * FROM A LEFT JOIN B ON A.A1 = B.B1 AND DATE(b.trt_date) = '2017-11-18' -- 把B表的条件移到ON里 WHERE a.tcs_type = 'SALES' ORDER BY a.tcs_no ASC;
这样一来,LEFT JOIN会先筛选出B表里符合日期条件的行,再和A表做关联。A表中找不到匹配的行依然会被保留,对应的B表字段全是NULL,这才是你想要的结果。
那为啥存入视图后就正常了?
这十有八九是你创建视图时的SQL语句,和你直接执行的查询不一样!比如你可能在写视图的SQL时,不小心把B表的日期条件移到了ON子句里,或者调整了条件的位置。你可以去Navicat/SQLyog里查看一下视图的定义语句,和你之前直接跑的查询对比一下,肯定能发现差异。当然,也不排除工具缓存的小概率情况,但最可能的还是视图的SQL逻辑更符合LEFT JOIN的正确用法。
内容的提问来源于stack exchange,提问作者padjee

