1. 程式人生 > 其它 >go where 不等於_on和where的過濾

go where 不等於_on和where的過濾

技術標籤:go where 不等於

之前一直沒在意,直到這個習題才發現掉坑了

表DistrictProducts

/* 練習題1-2-2:分地區排序 */
CREATE TABLE DistrictProducts
(district  VARCHAR(16) NOT NULL,
 name      VARCHAR(16) NOT NULL,
 price     INTEGER NOT NULL,
 PRIMARY KEY(district, name, price));

INSERT INTO DistrictProducts VALUES('東北', '橘子',	100);
INSERT INTO DistrictProducts VALUES('東北', '蘋果',	50);
INSERT INTO DistrictProducts VALUES('東北', '葡萄',	50);
INSERT INTO DistrictProducts VALUES('東北', '檸檬',	30);
INSERT INTO DistrictProducts VALUES('關東', '檸檬',	100);
INSERT INTO DistrictProducts VALUES('關東', '菠蘿',	100);
INSERT INTO DistrictProducts VALUES('關東', '蘋果',	100);
INSERT INTO DistrictProducts VALUES('關東', '葡萄',	70);
INSERT INTO DistrictProducts VALUES('關西', '檸檬',	70);
INSERT INTO DistrictProducts VALUES('關西', '西瓜',	30);
INSERT INTO DistrictProducts VALUES('關西', '蘋果',	20);

要求輸出

2df23df869c0cbdb360e31ea59875393.png
輸出應該是有問題的,原因在於關東的水果排序 檸檬(N)蘋果(P)菠蘿(B),這是什麼順序

作者提示三種解

  1. rank
#直接用rank來做

select district , name ,price , rank() over(PARTITION BY district order by price desc ) rank_1
from DistrictProducts 
order by district    ,price  desc 

2. 子查詢方式

#子查詢方式,作者也寫過
select   district , name ,price ,
(
select count(*)+1 
from DistrictProducts d2
where d2.district = d1.district 
and d2.price > d1.price 
) rank_1 
from DistrictProducts d1
order by d1.district , price desc ;

3. 自連線方式(作者提供·)

select d1.district ,d1.name,
       MAX(d1.price) AS price, 
       COUNT(d2.name) +1 AS rank_1
from 
DistrictProducts d1 
left join DistrictProducts d2 
on d1.district = d2.district 
and d1.price < d2.price 
 GROUP BY d1.district, d1.name
order by d1.district , d1.price desc ;

發現自己難以得到正確輸出的原因在於對ON和WHERE中相同過濾條件的結果認知不足

舉例如下:

集合1(記錄數為16)

select d1.district ,d1.name,
       d1.*,d2.*
from 
DistrictProducts d1 
left join DistrictProducts d2 
on d1.district = d2.district 
and d1.price < d2.price 

集合2(記錄數為11)

select d1.district ,d1.name,
       d1.*,d2.*
from 
DistrictProducts d1 
left join DistrictProducts d2 
on d1.district = d2.district 
where  d1.price < d2.price 

兩個集合完全不一致!

以例子中的表而言,

DistrictProducts d1 
left join DistrictProducts d2 
on d1.district = d2.district 

產生了41條記錄(計算如下)

select sum(count_pow)
from 
(
select district,pow(count(*),2) count_pow
from 
DistrictProducts d1 
group by district
)r 

隨後這41條記錄由於ON和WHERE過濾條件的緣故產生差異

LEFT JOIN ON的形式決定了左表每條記錄出現次數有且大於等於一次,如右表有對應於左表的記錄,則對應的左表返回右表對應的記錄,反之,則返回左表。

WHERE則是在這41條記錄的基礎上進行了布林判定,即返回TRUE的記錄。

故在類似的過濾條件下, LEFT JOIN ON的記錄數>=WHERE的記錄數。