日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

SQL进阶,子查询与窗口函数

發布時間:2023/12/19 数据库 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SQL进阶,子查询与窗口函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本節給大家講解SQL在實際過程中用途比較多的子查詢與窗口函數,下面一起學習。

示例工具:MySQL8.0、Navicat Premium 12

本文講解內容:子查詢與窗口函數

適用范圍:SQL進階應用

子查詢

子查詢用于為主查詢返回其所需數據,或者對檢索數據進行進一步的限制,通常將一個查詢(子查詢)的結果作為另一個查詢(主查詢)的數據來源或判斷條件,常見的子查詢有WHERE子查詢,HAVING子查詢,FROM子查詢,SELECT子查詢,EXISTS子查詢。

子查詢是一種嵌套在其他 SQL 查詢的 WHERE 子句中的查詢,可以在 SELECT、INSERT、UPDATE 和 DELETE 語句中,同邏輯運算符一起使用。

使用子查詢必須遵循以下幾個規則:

  • 子查詢必須括在圓括號中。

  • 子查詢的 SELECT 子句中只能有一個列。

  • 子查詢不能使用 ORDER BY,在子查詢中,GROUP BY 可以起到同 ORDER BY 相同作用。

  • 返回多行數據的子查詢只能同多值操作符一起使用,比如 IN 操作符。

  • 子查詢不能直接用在聚合函數中。

  • BETWEEN 不能同子查詢一起使用,但 BETWEEN 操作符可以用在子查詢中。

創建數據表

通常情況下子查詢都與 SELECT 語句一起使用,其基本語法如下所示:

SELECT?column_name?[,?column_name?] FROM???table1?[,?table2?] WHERE??column_name?OPERATOR?(SELECT?column_name?[,?column_name?]FROM?table1?[,?table2?][WHERE])

對于子查詢的數據演示創建兩個表,一個是薪水表,另一個是職位表,并且插入數據。

#創建薪水表SALARY CREATE?TABLE?SALARY? (ID?VARCHAR?(?10?), NAME?VARCHAR?(?10?), AGE?VARCHAR?(?10?), ADDRESS?VARCHAR?(?10?), SAL INT(10) );

給薪水表插入數據,數據內容如下所示:

#?給薪水表插入數據 INSERT?INTO?SALARY(ID,NAME,AGE,ADDRESS,SAL) VALUES ('C001','Rmesh',35,'Ahmedabad',2000), ('C002','Khilan',25,'Delhi',1500), ('C003','Kaushik',23,'Kota',2000), ('C004','Chaitali',25,'Mumbai',6500), ('C005','Hardik',27,'Bhopal',8500), ('C006','Komal',22,'MP',4500), ('C007','Tom',26,'MP',5500), ('C008','Muffy',24,'Indore',10000);

查詢所有的薪水數據如下所示:

SELECT * FROM SALARY;

同理創建一個職位表。

#創建職位表JOB CREATE TABLE JOB (JID?VARCHAR?(?10?), JB VARCHAR ( 10 ));

給職位表插入數據,數據內容如下所示:

#?給職位表插入數據 INSERT?INTO?JOB(JID,JB) VALUES ('C001','Teacher'), ('C002','Docter'), ('C003','Teacher'), ('C004','Worker'), ('C005','Nurse'), ('C006','Teacher'), ('C007','Docter'), ('C008','Teacher');

查詢所有的職位數據如下所示:

SELECT * FROM JOB;

子查詢過濾

子查詢最常見的使用是在WHERE子句的IN操作符中,以及用來填充計算列。先看一個簡單的例子,要查詢所有醫生的薪水情況,這里首先在職位表中查詢所有醫生的JID,查詢結果如下:

SELECT JID FROM JOB WHERE JB='Docter';

然后在薪水表中查詢ID為'C002','C007'的薪水情況,查詢結果如下:

SELECT SAL FROM SALARY WHERE ID IN('C002','C007');

這里使用子查詢更加簡便,子查詢從內向外依次處理,在下面的SELECT語句中,MySQL實際上執行了兩個操作,首先查詢返回兩個ID號:C002和C007。

然后,這兩個值以IN操作符要求的逗號分隔的格式傳遞給外部查詢的WHERE子句,可以看到輸出的結果是正確的,并且與前面WHERE子句所返回的值相同。

SELECT SAL FROM SALARY WHERE ID IN(SELECT JIDFROM JOBWHERE JB='Docter');

使用子查詢查詢薪水大于8000的員工的所有信息,首先內部查詢薪水大于8000的ID,然后外部使用一個WHERE查詢即可得到結果。

SELECT * FROM SALARY WHERE?ID?IN?(SELECT?IDFROM?SALARYWHERE SAL > 8000);

作為計算字段使用子查詢

使用子查詢的另一方法是創建計算字段,創建計算字段需要使用聚合函數,例如count,sum,avg,max,min等,這里首先計算平均薪水作為一個內查詢,然后在外部使用WHERE子句進行查詢,得出薪資比平均薪資低的員工的所有信息。

SELECT?* FROM?SALARY WHERE SAL < (SELECT AVG(SAL)FROM SALARY);

除使用WHERE過濾,還可以使用HAVING過濾,HAVING子句對分組統計函數進行過濾,也可以在HAVING子句中使用子查詢,要查詢薪資最高的人及其薪資情況,首先內部查詢最高工資,然后外部以人名分組后使用HAVING子句過濾,查詢結果如下。

SELECT NAME,SAL FROM SALARY GROUP BY NAME HAVING SAL = (SELECT MAX(SAL)FROM SALARY);

窗口函數

窗口函數與數據分組功能相似,可指定數據窗口進行統計分析,但窗口函數與數據分組又有所區別,窗口函數對每個組返回多行,而數據分組對每個組只返回一行;窗口函數指定分析函數工作的數據窗口大小,這個數據窗口大小可能會隨著行的變化而變化,而數據分組是針對所有數據進行統計,窗口函數的寫法如下。

<窗口函數>?over?(partition?by?<用于分組的列名>order?by?<用于排序的列名>)

窗口函數主要有兩種,一種是專用窗口函數,包括rank、dense_rank、row_number等。另一種是聚合函數,包括sum、avg、count、max、min等,下面逐一介紹窗口函數的五個功能,分別是聚合、排序、極值、移動、切片,下面一起來學習。

創建表

首先創建一個金額表,年份、姓名、國家設置為字符串類型,交易金額設置為整型。

#創建金額表pay CREATE TABLE pay (year?VARCHAR?(?10?), name VARCHAR ( 10 ), country VARCHAR ( 10 ), payment INT(10) );

給金額表插入數值。

# 給金額表插入數據 INSERT?INTO?pay(year,name,country,payment) VALUES (2017,'Lining','China',1119), (2018,'Lining','China',1176), (2018,'Zhaoqi','China',1388), (2019,'Zhaoqi','China',1597), (2018,'Jackie','USA',1028), (2019,'Jackie','USA',1934), (2020,'Jackie','USA',1837), (2017,'Tom','India',1578), (2018,'Tom','India',1329), (2019,'Tom','India',1578), (2020,'Tom','India',1399);

將所有的數據查詢出來結果如下所示。

SELECT?*?from?pay;

一、聚合

1、計算列表總金額

SELECT?*,?SUM(payment)?OVER()?as?Total_payment?from?pay;

計算當前列表的總金額可以使用窗口函數,sum是求和,over()中不添加參數,則對所有數據進行求和,輸出的結果都是15963。

2、計算各國家總金額

SELECT?*,?SUM(payment)?OVER()?as?Total_payment, SUM(payment) OVER(PARTITION by country) as country_payment from pay;

計算各國家總金額就要對各個國家分組,這里分組使用的是PARTITION by,PARTITION by的功能與GROUP BY的功能類似,指定按照那一列進行分組,用country分組求和,則每個country的輸出結果一致。

3、按國家降序累加求和金額

SELECT?*,?SUM(payment)?OVER()?as?Total_payment,SUM(payment)?OVER(PARTITION?by?country)?as?country_payment, SUM(payment) OVER(PARTITION by country ORDER BY payment DESC) as order_payment from pay;

這里使用SQL中常用的向下累計求和的方法,當使用order by時,沒有rows between則意味著窗口是從起始行到當前行,所以對不同國家進行累加求和操作。

4、不同國家人數計數

count()用于計數,與前面sum的用法基本一致,可以用count(distinct country)進行去重,如果用partition by進行分組,則分組后再計數。

SELECT *, COUNT(name) OVER() as Total_people, COUNT(name) OVER(PARTITION by country) as country_people from pay;

5、 不同國家平均金額

SELECT *, AVG(payment) OVER() as avg_payment, AVG(payment) OVER(PARTITION by country) as country_ayg_payment from pay;

使用avg聚合函數的用法與前面的聚合運算用法一致,PARTITION by同樣用來分組,這里分組后求均值。

6、各國家最低金額

SELECT *, MAX(payment) OVER() as Max_payment, MIN(payment) OVER(PARTITION by country) as country_min_payment from pay;

這里MAX(payment)函數對整個數據計算最大值,使用PARTITION by對于不同的國家分組后然后計算最小值。

二、排序

1、各國家按金額排序

使用窗口函數排序,會使用到三個函數,row_number,rank,dense_rank,他們的使用區別如下:

  • row_number從1開始,按照順序,生成分組內記錄的序列;

  • rank生成數據項在分組中的排名,排名相等會在名次中留下空位;

  • dense_rank生成數據項在分組中的排名,排名相等會在名詞中不會留下空位。

SELECT *, ROW_NUMBER()OVER(ORDER BY payment DESC) as '順序排序', RANK()OVER(ORDER BY payment DESC) as '秩排序', DENSE_RANK()over(ORDER BY payment DESC) as '數據排序' from pay;

row_number函數,按照行記錄的順序來排序,此處從1到11按順序排列;rank函數,在排名相等會在名次中留下空位,此處共同排名為第4名,同時忽略第5名,繼續往下排列;dense_rank排名相等會在名詞中不會留下空位此處共同排名為第4名,不忽略第5名,繼續往下排列。

三、極值

1、當前行金額最高的人

first_value截止當前行的第一個,last_value截止當前行的最后一個。

select *, first_value(name)over(order by payment desc) as max_id, first_value(name)over(order by payment asc) as min_id, last_value(name)over(order by payment desc) as min_id_1, last_value(name)over(partition by country order by payment desc rows between unbounded preceding and unbounded following) as level_min_id from pay;

first_value按分組排序后取范圍內第1個值,last_value取最后1個值,因為默認窗口的關系,last_value會隨著窗口的改變而改變,所以一般不用last_value,如果要用,則改變窗口為所有行,此處用來查詢當前金額最大的人,以及截至當前金額最小的人。

四、移動

1、按國家分組金額排名前1位和后1位人名

lag和lead是按照排序規則,取前多少位和后多少位,參數有3個,第1個是要取出來的列,第2個移動多少位,第3個是如果取不到,賦予的值,默認取不到是NULL。

select *, lag(name,1,null)over(partition by country order by payment desc) as lag_id, lead(name,1,'0')over(partition by country order by payment desc) as lead_id from pay;

五、切片

1、按金額切片

ntile(n)用于將分組數據按照順序切分成N片,返回當前切片值,ntile把有序分區中的行分發到指定數據的組中,各個組有編號,編號從1開始,對于每一行,ntile返回此行所屬的組的編號,ntile(3)表示將表切分為3組,ntile可以分組排序后切分,表示對當前的組內進行切分后排序。

select *, ntile(3) over(order by payment desc) as total_part, ntile(2)over(partition by country order by payment desc) as level_part from pay;

-?END -

對比Excel系列圖書累積銷量達15w冊,讓你輕松掌握數據分析技能,可以在全網搜索書名進行了解:

總結

以上是生活随笔為你收集整理的SQL进阶,子查询与窗口函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。