PostgreSQL 高級SQL(三) 窗口函數


本文是轉載,原文地址是:https://www.jianshu.com/p/7d0f0e9c821a

 

這一章節我們將了解postgresql 中聚合函數后面的over()子句,可能大家在工作的時候或多或少也涉及過over()子句的使用。

我們如果要實現一張這樣的報表,這張報表有四列,國家名字,年份,年份GDP,1960-2018年該國家的GDP均值,第四列的結果的目的就是要拿對應年份的GDP和總的均值的GDP做比較,那么我可能會寫出來這樣的SQL:

SELECT ff.country_name, "year", gdp, cc.averg
  FROM country_gdp_year_final ff
  LEFT JOIN (SELECT country_name, AVG(gdp) AS averg
               FROM country_gdp_year_final
              WHERE country_code = 'CHN'
              GROUP BY country_name) cc
    ON cc.country_name = ff.country_name
 WHERE ff.country_code = 'CHN';

 

可以看到如果我們要在報表中多出一樣這樣的均值列的話,原生的SQL就只能以這種相似的方式來獲取,然后做join,幸運的是PG為我們提供了這種原生的函數獲取這種結果集,talk is cheap,show you the code!

select country_name,"year",gdp,avg(gdp) over() from country_gdp_year_final ff where country_code='CHN';

over()子句又稱作窗口函數,這個窗口是將where 條件獲取的總的集合假想成一個窗口,並且avg(gdp) over()獲取的是這個假想集的平均值。

上面的例子中我們只是獲取了一個國家的數據,如果我們將where條件換成下面的條件的話

SELECT
	country_name,
	"year",
	gdp,
	AVG ( gdp ) OVER ( ) 
FROM
	country_gdp_year_final ff 
WHERE
	country_code IN ( 'CHN', 'JPN', 'USA', 'DEU', 'CAN', 'FRA' ) 
	AND "year" BETWEEN 2015 AND 2017;

從結果可以看到最后一列的結果並不是我們想要的當前國家在2015-2017這三年的均值,而是六個國家這三年的均值,若要想要獲得理想結果的話,我們只能借助於窗口函數的partition by 子句了,請看代碼,

SELECT
	country_name,
	"year",
	gdp,
	AVG ( gdp ) OVER ( PARTITION BY country_name ) 
FROM
	country_gdp_year_final ff  
WHERE
	country_code IN ( 'CHN', 'JPN', 'USA', 'DEU', 'CAN', 'FRA' ) 
	AND "year" BETWEEN 2015 AND 2017;

partition by country_name的作用是將總集合按照country_name划分為獨立的窗口,中國的avg=中國三年的gdp和/3得到的,partition by 的作用就是划分更小的假想集窗口,在這個窗口里面求平均值。上面的結果中每個國家的結果是按照年份降序排序的,這是一種巧合而已,如果我們想要每個窗口的數據按照年升序排序的話,我們可以在over里面加入 order by year asc ,代碼如下

SELECT
	country_name,
	"year",
	gdp,
	AVG ( gdp ) OVER ( PARTITION BY country_name ORDER BY YEAR ASC ) 
FROM
	country_gdp_year_final ff  
WHERE
	country_code IN ( 'CHN', 'JPN', 'USA', 'DEU', 'CAN', 'FRA' ) 
	AND "year" BETWEEN 2015 AND 2017;

年份是按照年份升序排序了但是數據不是原來的數據了。。。我們可以看到中國的窗口平均值變化了,並且三年的均值是不一樣的,很多新人看到這可能會很迷糊,為什么avg不是上面的三個一樣的值11497786437410.0000,而是不同的三個值呢,我們在這需要澄清以下,這個查詢所做的事情是計算到時間序列中一個特定時間點的平均值,

2015中國GDP平均值=2015年中國gdp/1,(按照時間升序計算到2015年中國均值GDP)

2016中國GDP平均值=(2015年中國gdp+2016年中國gdp)/2,(按照時間升序計算到2016年中共均值GDP)

2017中國GDP平均值=(2015年中國gdp+2016年中國gdp+2017年中國gdp)/3,(按照時間升序計算到2017年中國均值GDP)

如果我們想要的的是按照年份降序排序,但是均值是2015-2017三年的均值的話,我們可以去掉over里面的order by year,在where 后面加上這樣查詢order by country_name,year asc;

SELECT
	country_name,
	"year",
	gdp,
	AVG ( gdp ) OVER ( PARTITION BY country_name ) 
FROM
	country_gdp_year_final ff  
WHERE
	country_code IN ( 'CHN', 'JPN', 'USA', 'DEU', 'CAN', 'FRA' ) 
	AND "year" BETWEEN 2015 AND 2017 
ORDER BY
	country_name,YEAR ASC;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM