1. 程式人生 > >Mysql 中Left/Right join on後面and和where條件查詢的差異-Mysql SQL運算子是有優先順序

Mysql 中Left/Right join on後面and和where條件查詢的差異-Mysql SQL運算子是有優先順序

一、Mysql中Left/Right join on後面and和where條件查詢的差異

1、建兩張測試表,一張商戶定義表、一張商戶操作狀態明細表

1)商戶定義表

CREATE TABLE hope.merchant (
  MERCHANT_id varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

2)商戶操作明細表

CREATE TABLE trade_info (
  MERCHANT_NO varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  TRADE_STATUS varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  CREATE_TIME datetime DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

2.測試Left/Right join on後面and和where條件查詢的差異

普通left join演示

select a.MERCHANT_id,b.MERCHANT_NO,b.TRADE_STATUS from hope.merchant a left join hope.trade_info b
  on a.MERCHANT_id=b.MERCHANT_NO;

select count(1) from hope.merchant a left join hope.trade_info b
  on a.MERCHANT_id=b.MERCHANT_NO;--》82行資料

結果:可以看到,部分商戶在某段時間內事沒有任何操作的,所以,左表hope.merchant的商戶,沒有對應的操作,會用Null補足。

1)Left/Right join on後面帶and

 select a.MERCHANT_id,b.MERCHANT_NO,b.TRADE_STATUS,b.CREATE_TIME from hope.merchant a left join hope.trade_info b
  on a.MERCHANT_id=b.MERCHANT_NO and b.CREATE_TIME>'2018-12-19 19:00:00';

select count(1) from hope.merchant a left join hope.trade_info b
  on a.MERCHANT_id=b.MERCHANT_NO and b.CREATE_TIME>'2018-12-19 19:00:00';  ----》69行資料

2)Left/Right join on後面帶where

select a.MERCHANT_id,b.MERCHANT_NO,b.TRADE_STATUS,b.CREATE_TIME from hope.merchant a left join hope.trade_info b
  on a.MERCHANT_id=b.MERCHANT_NO where b.CREATE_TIME>'2018-12-19 19:00:00';

select count(1) from hope.merchant a left join hope.trade_info b
  on a.MERCHANT_id=b.MERCHANT_NO where b.CREATE_TIME>'2018-12-19 19:00:00'; --》43行資料

3)對比結果

語句一是on and ,一句是 on where,下的條件類似,但是結果卻是完全不同。帶where的過濾掉了左連線中左表沒有任何操作記錄的商戶號,

但是使用and的卻沒有,並得到了我想要的結果。Why???

 

二、Mysql 運算子是有優先順序

1.總結SQL優先順序

大家可能看出一些規律,在on的情況下and(或者or)與on同時對前面的集合起作用,而存在where的時候,先對集合進行on條件的抽取,在根據where的條件進行抽取.這是個值得注意的地方.
說下原因:
(1)ON後面的篩選條件主要是針對的是關聯表【而對於主表篩選條件不適用】;
(2)對於主表的篩選條件應放在where後面,不應該放在ON後面;
(3)對於關聯表我們要區分對待。如果是要條件查詢後才連線應該把查詢件放置於ON後;如果是想再連線完畢後才篩選就應把條件放置於where後面;
(4)對於關聯表我們其實可以先做子查詢再做join。

2.總結sql型別,儘量不寫子查詢

1)對於關聯表我們其實可以先做子查詢再做join,此SQL執行3.5秒

select MERCHANT_ID,case when rait is null then 0 else  rait end
from (
select MERCHANT_ID,
TRUNCATE(count(case when c.trade_status ='SUCCESS' then 1 else null end)*100/count(case when c.trade_status !='FAILED' then 1 else null end),2) rait 
from ifpay_ccpay.merchant a left join (
select * from ifpay_ccpay.trade_info b where b.CREATE_TIME > date_add(now(), interval - 30 minute)
and b.method='H5') c on a.MERCHANT_ID=c.MERCHANT_NO group by a.MERCHANT_ID) d;

2)不做子查詢執行14ms

select MERCHANT_ID,case when rait is null then 0 else  rait end
from (
select MERCHANT_ID,
TRUNCATE(count(case when b.trade_status ='SUCCESS' then 1 else null end)*100/count(case when b.trade_status !='FAILED' then 1 else null end),2) rait 
from ifpay_ccpay.merchant a left join ifpay_ccpay.trade_info b on a.MERCHANT_ID=b.MERCHANT_NO
and b.CREATE_TIME > date_add(now(), interval - 30 minute)
and b.method='H5'  group by a.MERCHANT_ID) D;