開窗函數(shù)有淺入深詳解(一)
在開窗函數(shù)出現(xiàn)之前存在著很多用 SQL 語句很難解決的問題,很多都要通過復(fù)雜的相關(guān)子查詢或者存儲(chǔ)過程來完成。為了解決這些問題,在2003年ISO SQL標(biāo)準(zhǔn)加入了開窗函數(shù),開窗函數(shù)的使用使得這些經(jīng)典的難題可以被輕松的解決。
目前在 MSSQLServer、Oracle、DB2 等主流數(shù)據(jù)庫中都提供了對(duì)開窗函數(shù)的支持,不過非常遺憾的是 MYSQL 暫時(shí)還未對(duì)開窗函數(shù)給予支持。
為了更加清楚地理解,我們來建表并進(jìn)行相關(guān)的查詢(截圖為MSSQLServer中的結(jié)果)
MYSQL,MSSQLServer,DB2:
CREATE TABLE T_Person ( FName VARCHAR(20), FCity VARCHAR(20), FAge INT, FSalary INT )
Oracle:
CREATE TABLE T_Person (FName VARCHAR2(20),FCity VARCHAR2(20), FAge INT,FSalary INT)
注:以下結(jié)果只在MSSQLServer中演示:
T_Person 表保存了人員信息,F(xiàn)Name 字段為人員姓名,F(xiàn)City 字段為人員所在的城市名,
FAge 字段為人員年齡,F(xiàn)Salary 字段為人員工資。
然后執(zhí)行下面的SQL語句向 T_Person表中插入一些演示數(shù)據(jù):
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Tom','BeiJing',20,3000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Tim','ChengDu',21,4000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Jim','BeiJing',22,3500);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Lily','London',21,2000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('John','NewYork',22,1000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('YaoMing','BeiJing',20,3000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Swing','London',22,2000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Guo','NewYork',20,2800);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('YuQian','BeiJing',24,8000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Ketty','London',25,8500);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Kitty','ChengDu',25,3000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Merry','BeiJing',23,3500);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Smith','ChengDu',30,3000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Bill','BeiJing',25,2000);
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Jerry','NewYork',24,3300);
查看表中的內(nèi)容:
select * from T_Person

開窗函數(shù)簡介
與 聚 合函數(shù)一樣,開窗函數(shù)也是對(duì)行集組進(jìn)行聚合計(jì)算,但是它不像普通聚合函數(shù)那樣每組只返回一個(gè)值,開窗函數(shù)可以為每組返回多個(gè)值,因?yàn)殚_窗函數(shù)所執(zhí)行聚合計(jì)算的行集組是窗口。
在ISO SQL規(guī)定了這樣的函數(shù)為開窗函數(shù),在 Oracle中則被稱為分析函數(shù),而在DB2中則被稱為OLAP函數(shù)。
要計(jì)算所有人員的總數(shù),我們可以執(zhí)行下面的 SQL語句:
SELECT COUNT(*) FROM T_Person
除了這種較簡單的使用方式,有時(shí)需要從不在聚合函數(shù)中的行中訪問這些聚合計(jì)算的值。比如我們想查詢每個(gè)工資小于 5000元的員工信息(城市以及年齡) ,并且在每行中都顯示所有工資小于5000元的員工個(gè)數(shù),嘗試編寫下面的 SQL語句:
SELECT FCITY , FAGE , COUNT(*) FROM T_Person HERE FSALARY<5000
執(zhí)行上面的SQL以后我們會(huì)得到下面的錯(cuò)誤信息:
選擇列表中的列 'T_Person.FCity' 無效,因?yàn)樵摿袥]有包含在聚合函數(shù)或 GROUP BY 子句中。
這是因?yàn)樗胁话诰酆虾瘮?shù)中的列必須聲明在GROUP BY 子句中,
可以進(jìn)行如下修改:
SELECT FCITY, FAGE, COUNT(*) FROM T_Person WHERE FSALARY<5000 GROUP BY FCITY , FAGE
執(zhí)行完畢我們就能在輸出結(jié)果中看到下面的執(zhí)行結(jié)果:

這個(gè)執(zhí)行結(jié)果與我們想像的是完全不同的,這是因?yàn)镚ROUP BY子句對(duì)結(jié)果集進(jìn)行了分組,所以聚合函數(shù)進(jìn)行計(jì)算的對(duì)象不再是所有的結(jié)果集,而是每一個(gè)分組。
可以通過子查詢來解決這個(gè)問題,SQL如下:
SELECT FCITY , FAGE , ( SELECT COUNT(* ) FROM T_Person WHERE FSALARY<5000 ) FROM T_Person WHERE FSALARY<5000
執(zhí)行完畢我們就能在輸出結(jié)果中看到下面的執(zhí)行結(jié)果:

雖然使用子查詢能夠解決這個(gè)問題,但是子查詢的使用非常麻煩,使用開窗函數(shù)則可以大大簡化實(shí)現(xiàn),下面的SQL語句展示了如果使用開窗函數(shù)來實(shí)現(xiàn)同樣的效果:
SELECT FCITY , FAGE , COUNT(*) OVER() FROM T_Person WHERE FSALARY<5000
執(zhí)行完畢我們就能在輸出結(jié)果中看到下面的執(zhí)行結(jié)果:

可以看到與聚合函數(shù)不同的是,開窗函數(shù)在聚合函數(shù)后增加了一個(gè)OVER 關(guān)鍵字。
開窗函數(shù)的調(diào)用格式為:
函數(shù)名(列) OVER(選項(xiàng))
OVER 關(guān)鍵字表示把函數(shù)當(dāng)成開窗函數(shù)而不是聚合函數(shù)。SQL 標(biāo)準(zhǔn)允許將所有聚合函數(shù)用做開窗函數(shù),使用OVER 關(guān)鍵字來區(qū)分這兩種用法。
在上邊的例子中,開窗函數(shù)COUNT(*) OVER()對(duì)于查詢結(jié)果的每一行都返回所有符合條件的行的條數(shù)。OVER關(guān)鍵字后的括號(hào)中還經(jīng)常添加選項(xiàng)用以改變進(jìn)行聚合運(yùn)算的窗口范圍。
如果OVER關(guān)鍵字后的括號(hào)中的選項(xiàng)為空,則開窗函數(shù)會(huì)對(duì)結(jié)果集中的所有行進(jìn)行聚合運(yùn)算。
總結(jié):上述講述的是開窗函數(shù)的基本用法,希望對(duì)大家有所幫助!
- SQLserver 實(shí)現(xiàn)分組統(tǒng)計(jì)查詢(按月、小時(shí)分組)
- SQL2005 學(xué)習(xí)筆記 窗口函數(shù)(OVER)
- sqlserver2005使用row_number() over分頁的實(shí)現(xiàn)方法
- SQL2005利用ROW_NUMBER() OVER實(shí)現(xiàn)分頁功能
- Sql Server 分組統(tǒng)計(jì)并合計(jì)總數(shù)及WITH ROLLUP應(yīng)用
- Sql Server:多行合并成一行,并做分組統(tǒng)計(jì)的兩個(gè)方法
- SQL進(jìn)行排序、分組、統(tǒng)計(jì)的10個(gè)新技巧分享
- sql server如何利用開窗函數(shù)over()進(jìn)行分組統(tǒng)計(jì)
相關(guān)文章
SQLServer代理中如何給操作員發(fā)送事件警報(bào)郵件
在所有的SQL?Server系統(tǒng)中至少要配置一個(gè)操作員,這會(huì)保證對(duì)于大多數(shù)嚴(yán)重錯(cuò)誤,一些特定的提醒會(huì)發(fā)給你,當(dāng)然,發(fā)送郵件警報(bào)的話需要SQL?Server能發(fā)送郵件警報(bào),另外,當(dāng)警報(bào)觸發(fā)時(shí)可以執(zhí)行作業(yè)意味著你可以通過自動(dòng)化操作修正很多常規(guī)錯(cuò)誤,而不需要每次都人為干預(yù)錯(cuò)誤發(fā)生2025-03-03
SQL?Server中的XML數(shù)據(jù)類型詳解
本文詳細(xì)講解了SQL?Server中的XML數(shù)據(jù)類型,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
SQL Server兩表數(shù)據(jù)同步的多種方法詳解
這篇文章主要介紹了SQL Server兩表數(shù)據(jù)同步的多種方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
遠(yuǎn)程連接局域網(wǎng)內(nèi)的sql server 無法連接 錯(cuò)誤與解決方法
下面我們依次介紹如何來解決這三個(gè)最常見的連接錯(cuò)誤。2009-09-09
如何把sqlserver數(shù)據(jù)遷移到mysql數(shù)據(jù)庫及需要注意事項(xiàng)
由于項(xiàng)目起初用的是sqlserver數(shù)據(jù)庫,后來改用了mysql數(shù)據(jù)庫,那么如何把sqlserver遷移mysql呢?對(duì)sqlserver數(shù)據(jù)庫遷移感興趣的朋友可以參考下本篇文章2015-10-10
SQL SERVER實(shí)現(xiàn)連接與合并查詢
本文詳細(xì)講解了SQL SERVER實(shí)現(xiàn)連接與合并查詢的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02

