1. 程式人生 > 其它 >Winform同一資料來源多個控制元件保持同步

Winform同一資料來源多個控制元件保持同步

5.1 視窗函式

5.1.1 視窗函式概念及基本的使用方法

視窗函式也稱為OLAP函式。OLAP 是OnLine AnalyticalProcessing 的簡稱,意思是對資料庫資料進行實時分析處理。

為了便於理解,稱之為視窗函式。常規的SELECT語句都是對整張表進行查詢,而視窗函式可以讓我們有選擇的去某一部分資料進行彙總、計算和排序。

視窗函式的通用形式:

<視窗函式> OVER ([PARTITION BY <列名>]
                     ORDER BY <排序用列名>)

*[]中的內容可以省略。
視窗函式最關鍵的是搞明白關鍵字PARTITON BY

ORDER BY的作用。

PARTITON BY是用來分組,即選擇要看哪個視窗,類似於GROUP BY 子句的分組功能,但是PARTITION BY 子句並不具備GROUP BY 子句的彙總功能,並不會改變原始表中記錄的行數。

ORDER BY是用來排序,即決定視窗內,是按那種規則(欄位)來排序的。

舉個栗子:

SELECT product_name
       ,product_type
       ,sale_price
       ,RANK() OVER (PARTITION BY product_type
                         ORDER BY sale_price) AS ranking
  FROM product

得到的結果是:

我們先忽略生成的新列 - [ranking], 看下原始資料在PARTITION BY 和 ORDER BY 關鍵字的作用下發生了什麼變化。

PARTITION BY 能夠設定視窗物件範圍。本例中,為了按照商品種類進行排序,我們指定了product_type。即一個商品種類就是一個小的"視窗"。

ORDER BY 能夠指定按照哪一列、何種順序進行排序。為了按照銷售單價的升序進行排列,我們指定了sale_price。此外,視窗函式中的ORDER BY與SELECT語句末尾的ORDER BY一樣,可以通過關鍵字ASC/DESC來指定升序/降序。省略該關鍵字時會預設按照ASC,也就是

升序進行排序。本例中就省略了上述關鍵字 。

5.2 視窗函式種類

大致來說,視窗函式可以分為兩類。

一是 將SUM、MAX、MIN等聚合函式用在視窗函式中

二是 RANK、DENSE_RANK等排序9用的專用視窗函式

5.2.1 專用視窗函式

  • RANK函式

計算排序時,如果存在相同位次的記錄,則會跳過之後的位次。

例)有 3 條記錄排在第 1 位時:1 位、1 位、1 位、4 位……

  • DENSE_RANK函式

同樣是計算排序,即使存在相同位次的記錄,也不會跳過之後的位次。

例)有 3 條記錄排在第 1 位時:1 位、1 位、1 位、2 位……

  • ROW_NUMBER函式

賦予唯一的連續位次。

例)有 3 條記錄排在第 1 位時:1 位、2 位、3 位、4 位

執行以下程式碼:

SELECT  product_name
       ,product_type
       ,sale_price
       ,RANK() OVER (ORDER BY sale_price) AS ranking
       ,DENSE_RANK() OVER (ORDER BY sale_price) AS dense_ranking
       ,ROW_NUMBER() OVER (ORDER BY sale_price) AS row_num
  FROM product

5.2.2 聚合函式在視窗函式上的使用

聚合函式在開窗函式中的使用方法和之前的專用視窗函式一樣,只是出來的結果是一個累計的聚合函式值。

執行以下程式碼:

SELECT  product_id
       ,product_name
       ,sale_price
       ,SUM(sale_price) OVER (ORDER BY product_id) AS current_sum
       ,AVG(sale_price) OVER (ORDER BY product_id) AS current_avg
  FROM product;

可以看出,聚合函式結果是,按我們指定的排序,這裡是product_id,當前所在行及之前所有的行的合計或均值。即累計到當前行的聚合。

5.3 視窗函式的的應用 - 計算移動平均

在上面提到,聚合函式在視窗函式使用時,計算的是累積到當前行的所有的資料的聚合。 實際上,還可以指定更加詳細的彙總範圍。該彙總範圍成為框架frame)

語法

<視窗函式> OVER (ORDER BY <排序用列名>
                 ROWS n PRECEDING )
                 
<視窗函式> OVER (ORDER BY <排序用列名>
                 ROWS BETWEEN n PRECEDING AND n FOLLOWING)

PRECEDING(“之前”), 將框架指定為 “截止到之前 n 行”,加上自身行

FOLLOWING(“之後”), 將框架指定為 “截止到之後 n 行”,加上自身行

BETWEEN 1 PRECEDING AND 1 FOLLOWING,將框架指定為 “之前1行” + “之後1行” + “自身”

執行以下程式碼:

SELECT  product_id
       ,product_name
       ,sale_price
       ,AVG(sale_price) OVER (ORDER BY product_id
                               ROWS 2 PRECEDING) AS moving_avg
       ,AVG(sale_price) OVER (ORDER BY product_id
                               ROWS BETWEEN 1 PRECEDING 
                                        AND 1 FOLLOWING) AS moving_avg  
  FROM product

執行結果:

注意觀察框架的範圍。

ROWS 2 PRECEDING:

ROWS BETWEEN 1 PRECEDINGAND 1 FOLLOWING:

5.3.1 視窗函式適用範圍和注意事項

  • 原則上,視窗函式只能在SELECT子句中使用。
  • 視窗函式OVER 中的ORDER BY 子句並不會影響最終結果的排序。其只是用來決定視窗函式按何種順序計算。

5.4 GROUPING運算子

5.4.1 ROLLUP - 計算合計及小計

常規的GROUP BY 只能得到每個分類的小計,有時候還需要計算分類的合計,可以用 ROLLUP關鍵字。

SELECT  product_type
       ,regist_date
       ,SUM(sale_price) AS sum_price
  FROM product
 GROUP BY product_type, regist_date WITH ROLLUP

得到的結果為:

這裡ROLLUP 對product_type, regist_date兩列進行合計彙總。結果實際上有三層聚合,如下圖 模組3是常規的 GROUP BY 的結果,需要注意的是衣服 有個註冊日期為空的,這是本來資料就存在日期為空的,不是對衣服類別的合計; 模組2和1是 ROLLUP 帶來的合計,模組2是對產品種類的合計,模組1是對全部資料的總計。

ROLLUP 可以對多列進行彙總求小計和合計。

練習題

5.1

請說出針對本章中使用的 product(商品)表執行如下 SELECT 語句所能得到的結果。

SELECT  product_id
       ,product_name
       ,sale_price
       ,MAX(sale_price) OVER (ORDER BY product_id) AS Current_max_price
  FROM product
product_id	product_name	sale_price	Current_max_price
0001	T恤	1000	1000
0002	打孔器	500	1000
0003	運動T恤	4000	4000
0004	菜刀	3000	4000
0005	高壓鍋	6800	6800
0006	叉子	500	6800
0007	擦菜板	880	6800
0008	圓珠筆	100	6800

5.2

繼續使用product表,計算出按照登記日期(regist_date)升序進行排列的各日期的銷售單價(sale_price)的總額。排序是需要將登記日期為NULL 的“運動 T 恤”記錄排在第 1 位(也就是將其看作比其他日期都早)

SELECT  product_id
       ,product_name
       ,sale_price
			 ,regist_date
       ,SUM(sale_price) OVER (ORDER BY regist_date) AS current_sum_sale
  FROM product

5.3

思考題

① 視窗函式不指定PARTITION BY的效果是什麼?

② 為什麼說視窗函式只能在SELECT子句中使用?實際上,在ORDER BY 子句使用系統並不會報錯。

① 如果不指定就會全表排序,不會分為一個個的小視窗
② 執行順序FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
視窗函式是為了動態分析處理,在SELECT子句可以進行篩選,而ORDER BY子句中只是用來排序,無法實現相應功能。