PostgreSQL 高級(jí)SQL(二) filter子句

????本章所用到案例數(shù)據(jù)來自于上一章節(jié),如果有想使用該數(shù)據(jù)的讀者可以查看上一章節(jié)。

? ? 這一章節(jié)我們想要了解的是PG聚合操作中使用到的filter子句,這個(gè)filter子句是ANSI SQL標(biāo)準(zhǔn)中的關(guān)鍵字,并不是PG的專用SQL關(guān)鍵字。如果我們想了解中國(guó)、美國(guó)、日本、法國(guó)、德國(guó)、加拿大從1960~2018年中每隔十年的GDP平均值情況,我們可能會(huì)寫出著這樣的SQL,

select country_name,sum(case when year>=1960 and year<1970 then gdp else null end) as "1960~1969", sum(case when year>=1970 and year<1980 then gdp else null end) as "1970~1979", sum(case when year>=1980 and year<1990 then gdp else null end) as "1980~1989", sum(case when year>=1990 and year<2000 then gdp else null end) as "1990~1999", sum(case when year>=2000 then gdp else null end) as "2000~至今" from country_gdp_year_final where country_code in('CHN','JPN','USA','DEU','CAN','FRA') group by country_name;

case when子句 實(shí)現(xiàn)六國(guó)每個(gè)十年的GDP總值

從上圖可以看出美國(guó)的經(jīng)濟(jì)體量和我們中國(guó)的經(jīng)濟(jì)體量不是在一個(gè)數(shù)量級(jí)的,中國(guó)每隔十年的GDP實(shí)現(xiàn)一倍的增速,美國(guó)一直飛速發(fā)展時(shí)期,中國(guó)要實(shí)現(xiàn)美國(guó)的GDP的話粗略估計(jì)需要至少30年的時(shí)間甚至更久;

回歸正題,我們今天的主角是filter子句,ANSI SQL加入filter關(guān)鍵詞的主要目的就是替代case when子句,簡(jiǎn)化case when參與的聚合語句,增加可可讀性,我們用同樣的filter 子句實(shí)現(xiàn)上面的case when參與的聚合操作。

select country_name,sum(gdp) filter(where? year>=1960 and year<1970) as "1960~1969",sum(gdp)? filter(where? year>=1970 and year<1980) as "1970~1979",sum(gdp)? filter(where year>=1980 and year<1990)? as "1980~1989",sum(gdp)? filter(where? year>=1990 and year<2000) as "1990~1999", sum(gdp)? filter(where? year>=2000 ) as "2000~至今" from country_gdp_year_final? where? country_code in('CHN','JPN','USA','DEU','CAN','FRA') group by country_name;

filter子句 實(shí)現(xiàn)六國(guó)每個(gè)十年的GDP總值? ?

從上面的結(jié)果我們可以看出filter子句和case when 子句在聚合函數(shù)中使用是等價(jià)的,并且filter子句的可讀性更好,讓人一眼就能看出SQL的目的和作用,

下面我們看一下上面?zhèn)z個(gè)語句的的執(zhí)行計(jì)劃:

case when聚合與filter聚合的查詢計(jì)劃

????????從上面的結(jié)果我們可以看出來倆種語句不僅結(jié)果一樣而且產(chǎn)生的執(zhí)行計(jì)劃也是一致的,并且倆個(gè)語句值進(jìn)行了一次權(quán)標(biāo)掃描就計(jì)算出了結(jié)果,在平時(shí)的開發(fā)中,很多開發(fā)者為了實(shí)現(xiàn)相同的結(jié)果可能要進(jìn)行五次權(quán)標(biāo)掃描,很可能會(huì)寫出以下的相同查詢結(jié)果但是不同性能的SQL?

select ff.country_name,ff."1960~1969",aa."1970~1979",bb."1980~1989",cc."1990~1999",dd."2000~至今" from (

select country_name,sum(gdp) as "1960~1969"? from country_gdp_year_final ff where? year>=1960 and year<1970 and? country_code in('CHN','JPN','USA','DEU','CAN','FRA')? group by country_name)as ff?

left join(select country_name,sum(gdp) as "1970~1979"? from country_gdp_year_final where? year>=1970 and year<1980 and? country_code in('CHN','JPN','USA','DEU','CAN','FRA')? group by country_name)as aa? on aa.country_name=ff.country_name

left join(select country_name,sum(gdp) as "1980~1989"? from country_gdp_year_final where? year>=1980 and year<1990 and? country_code in('CHN','JPN','USA','DEU','CAN','FRA') group by country_name)as bb? on bb.country_name=ff.country_name?

left join(select country_name,sum(gdp) as "1990~1999"? from country_gdp_year_final where? year>=1990 and year<2000and? country_code in('CHN','JPN','USA','DEU','CAN','FRA')? group by country_name)as cc? on cc.country_name=ff.country_name?

left join(select country_name,sum(gdp) as "2000~至今"? from country_gdp_year_final where year>=2000 and? country_code in('CHN','JPN','USA','DEU','CAN','FRA')? group by country_name)as dd? on dd.country_name=ff.country_name;


多次查詢獲得結(jié)果集

我也相信很多人開發(fā)者寫出來的SQL和上面的SQL基本差不多,這種SQL不僅很長(zhǎng)而且很難都,更致命的是這種SQL進(jìn)行了五次全表掃描,在不考慮緩存命中的的情況下,這種SQL的查詢時(shí)間是上面filter和case when子句的五倍,我們可以看一下這個(gè)長(zhǎng)SQL的查詢計(jì)劃。


多次查詢關(guān)聯(lián)獲取結(jié)果集的查詢計(jì)劃

????????從上面的查詢計(jì)劃我們可以看出來經(jīng)過了五次全表掃描,五次聚合,如果這個(gè)表的數(shù)據(jù)量很大,那么性能可想而知。

? ? ? ? 最后我想說的是filter適合所有的聚合函數(shù),不僅僅是PG內(nèi)置的的聚合函數(shù),還支持安裝擴(kuò)展包的聚合函數(shù),總之filter子句非常的棒?。。?/p>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容