国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

MySQL8新特性窗口函數詳解

開發 前端
窗口函數的應用場景很廣,可以完成許多數據分析與挖掘任務。MySQL8 支持窗口函數是一個非常棒的特性,大大提高了 MySQL 在數據分析領域的競爭力。

本文博主給大家詳細講解一波 MySQL8 的新特性:「窗口函數」,相信大伙看完一定能有所收獲??。

  • 本文提供的 sql 示例都是基于 MySQL8,由博主親自執行確保可用
  • 博主github地址:http://github.com/wayn111 ,歡迎大家關注,點個star

簡介

MySQL8 窗口函數是一種特殊的函數,它可以在一組查詢行上執行類似于聚合的操作,但是不會將查詢行折疊為單個輸出行,而是為每個查詢行生成一個結果。窗口函數可以用來處理復雜的報表統計分析場景,例如計算移動平均值、累計和、排名等。其中博主認為它展現的主要威力在于「它能夠讓我們在不修改原有語句輸出結果的基礎上,直接添加新的聚合字段」。

一. 語法解析

窗口函數語法如下:

window_function_name ( [argument1, argument2, ...] ) 
OVER  (
  [ PARTITION BY col1, col2, ... ]
  [ORDER BY col3, col4, ...]
  [ ROWS | RANGE frame_start AND frame_end ]
)

window_function_name

window_function_name 函數可以是聚合函數或者非聚合函數。MySQL8 支持以下幾類窗口函數,

  1. 序號函數:用于為窗口內的每一行生成一個序號,例如 ROW_NUMBER(),RANK(),DENSE_RANK() 等。
  2. 分布函數:用于計算窗口內的每一行在整個分區中的相對位置,例如 PERCENT_RANK(),CUME_DIST() 等。
  3. 前后函數:用于獲取窗口內的當前行的前后某一行的值,例如 LAG(),LEAD() 等。
  4. 頭尾函數:用于獲取窗口內的第一行或最后一行的值,例如 FIRST_VALUE(),LAST_VALUE() 等。
  5. 聚合函數:用于計算窗口內的某個字段的聚合值,例如 SUM(),AVG(),MIN(),MAX() 等。

圖片圖片

MySQL官網提供

OVER

OVER 關鍵字很重要,用來標識是否使用窗口函數,語法如下

over_clause:
    {OVER (window_spec) | OVER window_name}

兩種形式都定義了窗口函數應該如何處理查詢行。它們的區別在于窗口是直接在 OVER() 中定義,還是基于 window_name 在 OVER 字句可以重復使用。

  1. OVER() 常規用法,窗口規范直接出現在 OVER 子句中的括號之間。
  2. OVER window_name 基于 Named Windows,是由查詢中其他地方的 WINDOW 子句定義的窗口規范的名稱,可以重復使用。本文后續會進行講解。

PARTITION BY

PARTITION BY子句用來將查詢結果劃分為不同的分區,窗口函數在每個分區上分別執行,語法如下

partition_clause:
    PARTITION BY expr [, expr] ..

ORDER BY

ORDER BY 子句用來對每個分區內的查詢結果進行排序,窗口函數將按照排序后的順序進行計算,語法如下

order_clause:
    ORDER BY expr [ASC|DESC] [, expr [ASC|DESC]] ...

frame_clause

frame_clause 是窗口函數的一個可選子句,用來指定每個分區內的數據范圍,可以是靜態的或動態的。語法如下

frame_clause:
    frame_units frame_extent

frame_units:
    {ROWS | RANGE}

其中,frame_units表示窗口范圍的單位,可以是ROWS或RANGE。ROWS表示基于行數,RANGE表示基于值的大小。frame_extent表示窗口范圍的起始位置和結束位置,可以是以下幾種形式:

  • CURRENT ROW: 表示當前行。
  • UNBOUNDED PRECEDING: 表示分區中的第一行。
  • UNBOUNDED FOLLOWING: 表示分區中的最后一行。
  • expr PRECEDING: 表示當前行減去expr的值。
  • expr FOLLOWING: 表示當前行加上expr的值。

例如,如果指定了ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING,則表示窗口范圍包括當前行、前兩行和后一行。如果指定了RANGE BETWEEN 10 PRECEDING AND CURRENT ROW,則表示窗口范圍包括當前行和值在當前行減去10以內的所有行。如果沒有指定frame_clause,則默認為RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,即從分區開始到當前行。

圖片圖片

引用自網上

二. Named Windows

MySQL8的 Named Windows 是指在 WINDOW 子句中定義并命名的窗口,可以在 OVER 子句中通過窗口名來引用。使用 Named Windows 的好處是可以避免在多個OVER子句中重復定義相同的窗口,而只需要在 WINDOW 子句中定義一次,然后在 OVER 子句中引用即可。例如,下面的查詢使用了三個相同的窗口:

SELECT
  val,
  ROW_NUMBER () OVER (ORDER BY val) AS 'row_number',
  RANK () OVER (ORDER BY val) AS 'rank',
  DENSE_RANK () OVER (ORDER BY val) AS 'dense_rank'
FROM numbers;

可以使用Named Windows來簡化為:

SELECT
  val,
  ROW_NUMBER () OVER w AS 'row_number',
  RANK () OVER w AS 'rank',
  DENSE_RANK () OVER w AS 'dense_rank'
FROM numbers WINDOW w AS (ORDER BY val);

這樣就只需要在 WINDOW 子句中定義一個名為w的窗口,然后在三個OVER子句中引用它。

如果一個 OVER 子句使用了 OVER (window_name ...) 而不是 OVER window_name,則可以在引用的窗口名后面添加其他子句來修改窗口。例如,下面的查詢定義了一個包含分區的窗口,并在兩個 OVER 子句中使用不同的排序來修改窗口:

SELECT
  DISTINCT year, country,
  FIRST_VALUE (year) OVER (w ORDER BY year ASC) AS first,
  FIRST_VALUE (year) OVER (w ORDER BY year DESC) AS last
FROM sales WINDOW w AS (PARTITION BY country);

這樣就可以根據不同的排序來獲取每個國家的第一年和最后一年。

一個命名窗口的定義本身也可以以一個窗口名開頭。這樣可以實現窗口之間的引用,但不能形成循環。例如,下面的查詢定義了三個命名窗口,其中第二個和第三個都引用了第一個:

SELECT
  val,
  SUM(val) OVER w1 AS sum_w1,
  SUM(val) OVER w2 AS sum_w2,
  SUM(val) OVER w3 AS sum_w3
FROM numbers
WINDOW
  w1 AS (ORDER BY val),
  w2 AS (w1 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),
  w3 AS (w2 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW);

這樣就可以根據不同的范圍來計算每個值的累計和。

三. SQL 示例

下面以一個簡單的示例表來說明 MySQL8 窗口函數的用法,提前準備 sql 腳本如下

CREATE TABLE `sales` (
  `id` int NOT NULL,
  `year` int DEFAULT NULL,
  `country` varchar(20) DEFAULT NULL,
  `product` varchar(20) DEFAULT NULL,
  `profit` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (1, 2000, 'Finland', 'Computer', 1500);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (2, 2000, 'Finland', 'Phone', 100);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (3, 2001, 'Finland', 'Phone', 10);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (4, 2001, 'India', 'Calculator', 75);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (5, 2000, 'India', 'Calculator', 75);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (6, 2000, 'India', 'Computer', 1200);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (7, 2000, 'USA', 'Calculator', 75);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (8, 2000, 'USA', 'Computer', 1500);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (9, 2001, 'USA', 'Calculator', 50);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (12, 2002, 'USA', 'Computer', 1200);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (13, 2001, 'USA', 'TV', 150);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (14, 2002, 'USA', 'TV', 100);
INSERT INTO `test_db`.`sales` (`id`, `year`, `country`, `product`, `profit`) VALUES (15, 2001, 'USA', 'Computer', 1500);

這是一個銷售信息表,包含年份、國家、產品和利潤四個字段。讓我們基于窗口函數來進行一些統計分析,例如:

問題一

計算每個國家每年的總利潤,并按照國家和年份排序

SELECT year, country, 
SUM(profit) OVER (PARTITION BY country, year) AS total_profit
FROM sales
ORDER BY country, year;

輸出結果:

+------+---------+--------------+
| year | country | total_profit |
+------+---------+--------------+
| 2000 | Finland | 1600         |
| 2000 | Finland | 1600         |
| 2001 | Finland | 10           |
| 2000 | India   | 1275         |
| 2000 | India   | 1275         |
| 2001 | India   | 75           |
| 2000 | USA     | 1575         |
| 2000 | USA     | 1575         |
| 2001 | USA     | 1700         |
| 2001 | USA     | 1700         |
| 2001 | USA     | 1700         |
| 2002 | USA     | 1300         |
| 2002 | USA     | 1300         |
+------+---------+--------------+

可以看到,每個國家每年的總利潤都被計算出來了,但是沒有折疊為單個輸出行,而是為每個查詢行生成了一個結果。

在這里就體現出博主說的不修改原有結果的基礎上,添加聚合字段的威力。

問題二

計算每個國家每種產品的銷售排名,并按照國家和排名排序

SELECT country, product, profit, 
RANK() OVER (PARTITION BY country ORDER BY profit DESC) AS rank1
FROM sales
ORDER BY country, rank1;

輸出結果:

+---------+------------+--------+-------+
| country | product    | profit | rank1 |
+---------+------------+--------+-------+
| Finland | Computer   |   1500 |     1 |
| Finland | Phone      |    100 |     2 |
| Finland | Phone      |     10 |     3 |
| India   | Computer   |   1200 |     1 |
| India   | Calculator |     75 |     2 |
| India   | Calculator |     75 |     2 |
| USA     | Computer   |   1500 |     1 |
| USA     | Computer   |   1500 |     1 |
| USA     | Computer   |   1200 |     3 |
| USA     | TV         |    150 |     4 |
| USA     | TV         |    100 |     5 |
| USA     | Calculator |     75 |     6 |
| USA     | Calculator |     50 |     7 |
+---------+------------+--------+-------+

可以看到,每個國家每種產品的銷售排名都被計算出來了,使用了RANK()函數,它會給相同利潤的產品分配相同的排名,并跳過之后的排名。細心的朋友可能會發現相同國家產品的銷售排名重復之后,下一名會跳名次,如果不想這樣可以使用 DENSE_RANK() 函數,

mysql> SELECT country, product, profit, 
DENSE_RANK() OVER (PARTITION BY country ORDER BY profit DESC) AS rank1
FROM sales
ORDER BY country, rank1;
+---------+------------+--------+-------+
| country | product    | profit | rank1 |
+---------+------------+--------+-------+
| Finland | Computer   |   1500 |     1 |
| Finland | Phone      |    100 |     2 |
| Finland | Phone      |     10 |     3 |
| India   | Computer   |   1200 |     1 |
| India   | Calculator |     75 |     2 |
| India   | Calculator |     75 |     2 |
| USA     | Computer   |   1500 |     1 |
| USA     | Computer   |   1500 |     1 |
| USA     | Computer   |   1200 |     2 |
| USA     | TV         |    150 |     3 |
| USA     | TV         |    100 |     4 |
| USA     | Calculator |     75 |     5 |
| USA     | Calculator |     50 |     6 |
+---------+------------+--------+-------+

問題三

計算每個國家每種產品的累計利潤,并按照國家和利潤排序

SELECT country, product, profit, 
SUM(profit) OVER (PARTITION BY country ORDER BY profit 
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_profit
FROM sales
ORDER BY country, profit;

輸出結果:

+---------+------------+--------+-------------------+
| country | product    | profit | cumulative_profit |
+---------+------------+--------+-------------------+
| Finland | Phone      |     10 | 10                |
| Finland | Phone      |    100 | 110               |
| Finland | Computer   |   1500 | 1610              |
| India   | Calculator |     75 | 75                |
| India   | Calculator |     75 | 150               |
| India   | Computer   |   1200 | 1350              |
| USA     | Calculator |     50 | 50                |
| USA     | Calculator |     75 | 125               |
| USA     | TV         |    100 | 225               |
| USA     | TV         |    150 | 375               |
| USA     | Computer   |   1200 | 1575              |
| USA     | Computer   |   1500 | 3075              |
| USA     | Computer   |   1500 | 4575              |
+---------+------------+--------+-------------------+

可以看到,每個國家每種產品的累計利潤都被計算出來了,使用了SUM()函數,并指定了ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW作為窗口范圍,表示從分區開始到當前行。

問題四

基于Named Window 重寫問題三,sql 如下

SELECT country, product, profit, 
SUM(profit) OVER w1 AS cumulative_profit
FROM sales
WINDOW
  w1 as (PARTITION BY country ORDER BY profit 
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
ORDER BY country, profit
;

輸出結果:

+---------+------------+--------+-------------------+
| country | product    | profit | cumulative_profit |
+---------+------------+--------+-------------------+
| Finland | Phone      |     10 | 10                |
| Finland | Phone      |    100 | 110               |
| Finland | Computer   |   1500 | 1610              |
| India   | Calculator |     75 | 75                |
| India   | Calculator |     75 | 150               |
| India   | Computer   |   1200 | 1350              |
| USA     | Calculator |     50 | 50                |
| USA     | Calculator |     75 | 125               |
| USA     | TV         |    100 | 225               |
| USA     | TV         |    150 | 375               |
| USA     | Computer   |   1200 | 1575              |
| USA     | Computer   |   1500 | 3075              |
| USA     | Computer   |   1500 | 4575              |
+---------+------------+--------+-------------------+

四. 窗口函數優缺點

優點:

  • 窗口函數可以在不改變原表行數的情況下,對每個分區內的查詢行進行聚合、排序、排名等操作,提高了數據分析的靈活性和效率。
  • 窗口函數可以使用滑動窗口來處理動態的數據范圍,例如計算移動平均值、累計和等。
  • 窗口函數可以與普通聚合函數、子查詢等結合使用,實現更復雜的查詢邏輯。

缺點:

  • 窗口函數的語法較為復雜,需要注意OVER子句中的各個參數的含義和作用。
  • 窗口函數的執行效率可能不如普通聚合函數,因為它需要對每個分區內的每個查詢行進行計算,而不是折疊為單個輸出行。
  • 窗口函數只能在SELECT列表和ORDER BY子句中使用,不能用于WHERE、GROUP BY、HAVING等子句中。

五、總結

窗口函數的應用場景很廣,可以完成許多數據分析與挖掘任務。MySQL8 支持窗口函數是一個非常棒的特性,大大提高了 MySQL 在數據分析領域的競爭力。希望通過這篇文章可以幫助大家對 MySQL8 的窗口函數有一個初步的認識。

責任編輯:武曉燕 來源: waynblog
相關推薦

2014-04-16 07:43:31

Java 8JRE

2014-07-15 14:12:17

Java8

2013-07-29 15:13:35

2021-02-22 11:51:15

Java開發代碼

2021-09-27 06:50:06

MySQL參數持久化

2014-07-15 14:48:26

Java8

2020-05-14 11:19:19

降序索引子集

2012-01-09 16:00:56

2009-07-27 09:46:28

Silverlight

2009-06-29 17:42:03

Tapestry5新特

2014-10-20 13:57:59

JavaFX 8Java 8

2013-04-09 12:59:21

WindowsPhon

2024-04-18 08:04:47

ElectronChrome升級

2011-02-21 16:39:47

Android 2.3Android R5

2010-06-23 15:29:52

Eclipse 3.6Java

2014-07-14 11:34:53

Java 8Nashorn

2009-01-16 10:01:57

MySQL復制特性測試

2011-05-07 16:08:29

Windows 8

2022-12-09 07:48:10

Java8Stream表達式

2022-12-30 09:24:23

Java8Stream操作
點贊
收藏

51CTO技術棧公眾號

色哟哟网站入口亚洲精品| 一区二区三区四区不卡| 亚洲伦理影院| 日韩欧美亚洲范冰冰与中字| 99久热在线精品视频| 青娱乐精品视频| 99久久伊人精品影院| 久久国产精品成人免费观看的软件| 久久99精品久久久久久琪琪| 欧美xnxx| 一区二区福利视频| 日韩av官网| 日韩免费高清av| 日韩精品毛片| 日韩精品一区二区三区视频| 黄色片在线播放| 亚洲国产一区二区三区| h片免费观看| 日韩美女久久久| 国产免费视频| 亚洲成a人v欧美综合天堂下载| www.99re.av| 亚洲精品成a人| 日本在线免费观看视频| 一区二区三区在线免费观看| 亚洲永久精品免费| 午夜欧美一区二区三区在线播放| 波多野结衣在线| 日韩欧美国产成人| 麻豆传媒在线免费看| 日韩欧美一级在线播放| 欧美人与性动交α欧美精品济南到| 精品日韩在线观看| 欧美成人免费电影| 欧美成人网在线| 日韩深夜福利| 亚洲自拍偷拍第一页| 国产精品一卡| 手机福利在线视频| 91丝袜国产在线播放| 色噜噜狠狠一区二区| 亚洲在线成人精品| av电影在线观看网址| 国产精品三级a三级三级午夜| 国产午夜精品一区二区| 日韩美女写真福利在线观看| 免费人成在线观看播放视频| 在线播放91灌醉迷j高跟美女| 在线黄色网页| 日韩精品亚洲专区| 香蕉视频在线观看网站| 午夜在线成人av| 国产中文在线视频| 久久精品亚洲精品国产欧美| www.激情网| 中文字幕第一区综合| 翔田千里在线视频| 欧美日韩一区二区三区四区在线观看 | 久久国内精品一国内精品| 久久91超碰青草在哪里看| 国产91|九色| 在线看片一区| 穿情趣内衣被c到高潮视频| 欧美国产综合色视频| h精品动漫在线观看| 精品国产乱码久久久久久久| 777久久精品| 蜜桃av噜噜一区二区三区| 97久久精品人人爽人人爽蜜臀| 五月伊人六月| 亚洲香蕉成视频在线观看| 九九视频精品全部免费播放| 日韩精品久久久免费观看| 中文字幕一区视频| a√中文在线观看| 青草青草久热精品视频在线网站| 日韩 欧美一区二区三区| 国产成人午夜电影| 亚洲欧洲一区二区三区在线观看| 成人免费电影网址| www成人免费| 欧美中文字幕一二三区视频| 亚洲成人高清| 欧洲久久久久久| 欧美爱爱视频| 欧美精品成人一区二区在线观看| 中文字幕亚洲视频| 日韩不卡视频在线观看| 亚洲自拍中文字幕| 欧美激情综合五月色丁香| 亚洲丝袜精品| 国产视频观看一区| 91麻豆高清视频| www欧美xxxx| 666精品在线| 一区二区成人在线视频| 国产亚洲精彩久久| 色狠狠久久av五月综合| 精品久久久中文| 91国内精品| 青青草视频国产| 欧美v日韩v国产v| 亚洲国产日本| 亚洲女人视频| 国产精品wwww| 亚洲日本青草视频在线怡红院| 亚洲成人不卡| 亚洲电影一二三区| 日韩午夜三级在线| 影音先锋亚洲电影| 日韩欧美电影在线观看| 国产精品69久久久久| 国产欧美精品一区二区三区四区| 日韩久久一区二区三区| 一本一生久久a久久精品综合蜜| 欧美网站一区二区| 一区二区影院| 毛片在线播放网址| 91手机在线播放| 色综合久久中文字幕| 午夜精品一区二区三区国产| 日本视频二区| 国产精品xxxxx| 亚洲一区二区欧美激情| 超碰成人久久| 日本一卡二卡四卡精品| 成人妇女淫片aaaa视频| 亚洲午夜久久久久| 亚洲免费二区| 在线免费观看黄色网址| 国产精品theporn88| 欧美精品免费在线观看| 亚洲自拍偷拍图区| 亚洲一区精品在线| 裸体素人女欧美日韩| 久cao在线| 裸体大乳女做爰69| 国产+人+亚洲| 欧美一级二级三级乱码| 26uuu久久综合| 亚洲欧美大片| 久久久人成影片一区二区三区| zzijzzij亚洲日本少妇熟睡| 日韩经典一区| 日韩毛片在线免费看| 国内揄拍国内精品少妇国语| 国产精品久久久久婷婷二区次| 最新精品国偷自产在线| 污黄视频在线看| 国产区日韩欧美| 精品国产乱码久久久久久1区2区 | 一级毛片aaaaaa免费看| 国产精品黄视频| 在线免费不卡电影| 久久夜色精品| 韩日精品一区二区| 蜜臀av免费观看| 91性高湖久久久久久久久_久久99| 欧美午夜精品理论片a级按摩| 日韩精品高清不卡| 999久久久国产999久久久| 国产黄色影视| 久久大香伊蕉在人线观看热2| 精品美女在线播放| 久久亚区不卡日本| 天天精品视频| 亚洲欧美一区二区三区| 91看片就是不一样| 3d精品h动漫啪啪一区二区| 精品久久久久久久久久久久久久久 | lutube成人福利在线观看| 婷婷久久伊人| 欧美人与性动交| 午夜视频一区在线观看| 99精品视频免费观看视频| 精品3atv在线视频| 男人的天堂网av| 视频一区二区三区在线观看| 欧美激情在线视频二区| 欧美日韩一区 二区 三区 久久精品| 国产大陆精品国产| 香蕉久久网站| 色综合.com| 欧美日韩欧美| jizz性欧美23| 日韩av电影资源网| 欧美一区二区三区免费观看视频| 欧美高清在线一区二区| 国产亚洲精品福利| 久久久精品国产免大香伊| 午夜影院在线观看欧美| 亚洲三级免费电影| 伊人夜夜躁av伊人久久| 福利视频导航一区| 超碰成人97| av网址在线看| 在线手机福利影院| 久久久久久久久久久综合| 亚洲一区二区在线播放| 欧美人与性动交|