差集并集的各种变式(join

A left join B on a.key=b.key

即使a.key为null也会显示数据,牢牢记住:会显示A的所有数据!! 

差集并集的各种变式(join_第1张图片

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

 

 

你可能感兴趣的:(Datawhale之MySQL)