A left join B on a.key=b.key
即使a.key为null也会显示数据,牢牢记住:会显示A的所有数据!!
left join/right join/inner join/full outer join
注意使用left join之类的可能会有A表有keyB表没key,所以join之后会存在一些key的有关B的数据为null的情形
敲黑板!这个时候再使用where条件去过滤的时候就很容易出bug,因为b表的一些数据为null,不参与比较条件,那么这一部分数据就被全部过滤掉了,那你left join和join的形式就没差别,从而就错了,这个时候解决办法是再嵌套一层。
总结一下:当left join/full outer join连接后出现null但却是需要这个有null的字段用于where比较的时候,
解决办法:将那个含有null的字段根据业务强行填充一个数(再嵌套一层填充)变成没有null之后再where比较即可
强行改变null的方法除了再嵌套一层,还有colesce(column,0)代表将column的null都变成0
比如下面这个语句,背景:bh_dw.dwd_bh_ord_info_view_intern 是每天很多车的订单表,是大表
bh_dw.dwd_bh_op_record_view_intern是每天很多车的报修表,是小表(因为很多车不一定报修)
a这个表是像这样:给报修的车辆(vid)赋予一个最近一次报修时间,如果报修时间离现在(0606)超过30天,就将报修时间直接设定0506(人工确定一个时间窗口不要太长)
b表left join 到a表,这一步也是没错的,
但是错就错在连接之后的where b.pt >= a.lastpt,这个是想说,保证b表的车辆骑行时间是再a的lastpt之后的,
乍一看没啥错误,但是你要想,b和aleft join之后,b的一些id对应的lastpt是null,所以你 b.pt >= a.lastpt会使得那些null的vid没也没有了,这样数据一下少了很多,
逻辑是这样的(报修车辆再30天内,报修车辆再30天外,车辆没有报修记录)
车辆没有报修记录的应该也设置一个lastpt(而不仅仅是null)
所以做法是再嵌套一层
select
a.vehicle_id
,b.city_id
,b.pt
,count(*) as last_repair_everyday_ord
from
(
select
*
from
bh_dw.dwd_bh_ord_info_view_intern
where
pt <= '2019-06-06'
) as b
left join
(
select
vehicle_id
,(case when datediff('2019-06-06',max(pt)) <= 30 then max(pt)
else '2019-05-06'
end )as lastpt
from
bh_dw.dwd_bh_op_record_view_intern
where
pt <= '2019-06-06'
and opt_type = 6
and sub_opt_type = 5
group by
vehicle_id
) as a
on
a.vehicle_id = b.vehicle_id
where
b.pt >= a.lastpt
and b.status = 5
group by
a.vehicle_id
,b.city_id
,b.pt
再嵌套一层的结果
select
*
,distance/(unix_timestamp(order_end_time) - unix_timestamp(order_start_time)) as speed
from
bh_dw.dwd_bh_ord_info_view_intern
where
pt <= '2019-06-06'
) as b
left join
(
select
a2.vehicle_id
,(case when datediff('2019-06-06',max(pt)) <= 30 then max(pt)
when max(pt) is null then '2019-05-06'
else '2019-05-06'
end )as lastpt
from
bh_dw.dwd_bh_op_record_view_intern as a1
right join
(
select
vehicle_id
from
bh_dw.dwd_bh_ord_info_view_intern
where
pt <= '2019-06-06'
) as a2
on a1.vehicle_id = a2.vehicle_id
and opt_type = 6
and sub_opt_type = 5
where
pt <= '2019-06-06'
group by
a2.vehicle_id
) as a
on
a.vehicle_id = b.vehicle_id
where
and b.pt >= a.lastpt
and b.status = 5
group by
a.vehicle_id
,b.city_id
,b.pt
就是先讲两个表连接,让那个每一个vid都有一个lastpt之后再比较,on的时候是除了两个id之外还有两个条件opt和subopt注意这两个条件要放在on上不要放在where上
下面这样放在where上就不行,因为两个条件只有小表有,大表没有!!!!!,所以where就过滤掉了,还是没效果哦
select
a2.vehicle_id
,(case when datediff('2019-06-06',max(pt)) <= 30 then max(pt)
when max(pt) is null then '2019-05-06'
else '2019-05-06'
end )as lastpt
from
bh_dw.dwd_bh_op_record_view_intern as a1
right join
(
select
vehicle_id
from
bh_dw.dwd_bh_ord_info_view_intern
where
pt <= '2019-06-06'
) as a2
on a1.vehicle_id = a2.vehicle_id
where
pt <= '2019-06-06'
and opt_type = 6
and sub_opt_type = 5
group by
a2.vehicle_id