一、join
在多表關聯查詢場景中,join是常用的方式。join,漢譯爲“連接”。連接分爲內連接(inner join)和外連接(out join)。外連接分爲左外連接和右外連接和全外連接,它們由分別簡稱爲“左連接(left join)”、“右連接(right join)”和“全連接(full join)”。當只使用關鍵字“join”時,等同於內連接(inner join)。
0.準備數據
-- 1.學生表:學號,姓名,性別,年齡
-- 1)建表:
create table t_student(p_id int(4),name varchar(10),gender char(2),age int(2));
-- 2)插入數據:
insert into t_student values (1,'小紅','女',13);
insert into t_student values (2,'小明','男',14);
insert into t_student values (4,'小劉','男',13);
-- 2.考試成績表:學號,語文成績,數學成績,英語成績,學期,學年
-- 1)建表:
create table t_result(student_id int(4),chinese_result int(3),math_result int(3),english_result int(3),trimester int(1),year int(4));
-- 2)插入數據:
insert into t_result values (1,95,69,98,1,2019);
insert into t_result values (1,97,77,95,2,2019);
insert into t_result values (1,95,80,90,1,2020);
insert into t_result values (1,86,73,91,2,2020);
insert into t_result values (2,68,89,49,1,2019);
insert into t_result values (2,74,96,66,1,2020);
insert into t_result values (2,85,98,59,2,2020);
insert into t_result values (3,95,99,99,1,2019);
insert into t_result values (3,96,100,100,2,2019);
insert into t_result values (3,97,100,100,1,2020);
insert into t_result values (3,98,100,100,2,2020);
1.內連接(inner join)or join
select t1.name,t2.chinese_result,t2.math_result,t2.english_result,t2.trimester,t2.year
from t_student t1 join t_result t2
on t1.p_id=t2.student_id;
select t1.name,t2.chinese_result,t2.math_result,t2.english_result,t2.trimester,t2.year
from t_student t1 inner join t_result t2
on t1.p_id=t2.student_id;
查詢結果:
2.left join
select t1.name,t2.chinese_result,t2.math_result,t2.english_result,t2.trimester,t2.year
from t_student t1 left join t_result t2
on t1.p_id=t2.student_id;
查詢結果:
3.right join
select t1.name,t2.chinese_result,t2.math_result,t2.english_result,t2.trimester,t2.year
from t_student t1 RIGHT join t_result t2
on t1.p_id=t2.student_id;
查詢結果:
4.full join
select t1.name,t2.chinese_result,t2.math_result,t2.english_result,t2.trimester,t2.year
from t_student t1 left join t_result t2
on t1.p_id=t2.student_id
union
select t1.name,t2.chinese_result,t2.math_result,t2.english_result,t2.trimester,t2.year
from t_student t1 RIGHT join t_result t2
on t1.p_id=t2.student_id;
-- 由於我使用的是MySQL數據庫服務,其不支持“full join”
-- 因此我們使用left join + union + right join來實現(上面一段代碼)。等同於:
select t1.name,t2.chinese_result,t2.math_result,t2.english_result,t2.trimester,t2.year
from t_student t1 full join t_result t2
on t1.p_id=t2.student_id;
5.小結
5.0 原始數據
5.1 inner join
5.2 left join
5.3 right join
5.4 full join
二、開窗函數
0.數據準備
數據表(Oracle):T_Person 表保存了人員信息,FName 字段爲人員姓名,FCity 字段爲人員所在的城市名,FAge 字段爲人員年齡,FSalary 字段爲人員工資
-- 1)建表
CREATE TABLE T_Person (FName string,FCity string,FAge INT,FSalary INT)
row format delimited fields terminated by ',';
-- 2)插入數據
INSERT INTO T_Person VALUES('Tom','BeiJing',20,3000);
INSERT INTO T_Person VALUES('Tim','ChengDu',21,4000);
INSERT INTO T_Person VALUES('Jim','BeiJing',22,3500);
INSERT INTO T_Person VALUES('Lily','London',21,2000);
INSERT INTO T_Person VALUES('John','NewYork',22,1000);
INSERT INTO T_Person VALUES('YaoMing','BeiJing',20,3000);
INSERT INTO T_Person VALUES('Swing','London',22,2000);
INSERT INTO T_Person VALUES('Guo','NewYork',20,2800);
INSERT INTO T_Person VALUES('YuQian','BeiJing',24,8000);
INSERT INTO T_Person VALUES('Ketty','London',25,8500);
INSERT INTO T_Person VALUES('Kitty','ChengDu',25,3000);
INSERT INTO T_Person VALUES('Merry','BeiJing',23,3500);
INSERT INTO T_Person VALUES('Smith','ChengDu',30,3000);
INSERT INTO T_Person VALUES('Bill','BeiJing',25,2000);
INSERT INTO T_Person VALUES('Jerry','NewYork',24,3300);
1.聚合開窗函數
聚合開窗函數可以使用SUM、AVG、MAX、MIN、COUNT等聚合函數,但是需要注意聚合開窗函數只能使用PARTITION BY子句,ORDER BY不能與聚合開窗函數一同使用。
1.1 求滿足條件的數據的總行數
count(*)over()
查詢每個工資小於 5000 元的員工信息(城市以及年齡),並且在每行中都顯示所有工資小於 5000 元的員工個數:
select fname, fcity, fsalary,
count(*) over() a -- 總人數
from t_person
where fsalary < 5000;
-- 類似於如下 使用子查詢 實現的效果:
select fname,
fcity,
fsalary,
(select count(*) from t_person where fsalary < 5000) -- 工資少於5000員工總數
from t_person
where fsalary < 5000;
運行結果:
Guo NewYork 2800 13
Swing London 2000 13
YaoMing BeiJing 3000 13
John NewYork 1000 13
Lily London 2000 13
Jim BeiJing 3500 13
Jerry NewYork 3300 13
Bill BeiJing 2000 13
Smith ChengDu 3000 13
Merry BeiJing 3500 13
Kitty ChengDu 3000 13
Tim ChengDu 4000 13
Tom BeiJing 3000 13
1.2 求各個分區的總行數
count(*) over(partition by fcity)
select fname,
fcity,
fage,
fsalary,
count(*) over(partition by fcity) a -- 所在分區的行數
from t_person;
運行結果:
Tom BeiJing 20 3000 6
YuQian BeiJing 24 8000 6
YaoMing BeiJing 20 3000 6
Jim BeiJing 22 3500 6
Bill BeiJing 25 2000 6
Merry BeiJing 23 3500 6
Kitty ChengDu 25 3000 3
Tim ChengDu 21 4000 3
Smith ChengDu 30 3000 3
Lily London 21 2000 3
Swing London 22 2000 3
Ketty London 25 8500 3
Jerry NewYork 24 3300 3
Guo NewYork 20 2800 3
John NewYork 22 1000 3
1.3 求到當前行 對應列 的數值之和
sum(fsalary) over(order by fsalary rows between unbounded preceding and current row) a
(註解:unbounded preceding -- 無上界,從第一行開始;current row -- 當前行)
select fname,
fcity,
fage,
fsalary,
sum(fsalary) over(order by fsalary rows between unbounded preceding and current row) a -- 到當前行工資的和
from t_person;
運行結果:
John NewYork 22 1000 1000
Swing London 22 2000 3000
Lily London 21 2000 5000
Bill BeiJing 25 2000 7000
Guo NewYork 20 2800 9800
Smith ChengDu 30 3000 12800
Kitty ChengDu 25 3000 15800
YaoMing BeiJing 20 3000 18800
Tom BeiJing 20 3000 21800
Jerry NewYork 24 3300 25100
Jim BeiJing 22 3500 28600
Merry BeiJing 23 3500 32100
Tim ChengDu 21 4000 36100
YuQian BeiJing 24 8000 44100
Ketty London 25 8500 52600
1.4 小結
聚合函數() over()這裏的“聚合函數() over()”,前者“聚合函數()”用來控制“對哪些列?做什麼聚合?”,後者“over()”表示“對哪些行?”。
聚合函數
聚合函數可以使用SUM、AVG、MAX、MIN、COUNT等聚合函數,來實現聚合操作。
控制列
列通過在調用聚合函數時傳入實參(函數後面的括號)來指定。
控制行
行通過over()的括號中傳入“一些操作”來實現。一些操作:可以是空,表示*,即對所有數據進行聚合操作;可以是分區函數“PARTITION BY”子句用來定義“在行的分區內部進行聚合計算”。
2.排名開窗函數
2.1 各排名函數的特點
特點 |
函數名 |
排名並列算兩個 |
rank() |
排名並列算一個 |
dense_rank() |
排名不併列 |
row_number() |
例如:
姓名 |
地區 |
分數 |
rank |
dense_rank |
row_number |
小李 |
安徽 |
91 |
1 |
1 |
1 |
小丁 |
安徽 |
90 |
2 |
2 |
2 |
小趙 |
安徽 |
90 |
2 |
2 |
3 |
小丑 |
安徽 |
77 |
4 |
3 |
4 |
小甲 |
安徽 |
68 |
5 |
4 |
5 |
小子 |
廣東 |
98 |
1 |
1 |
1 |
小卯 |
廣東 |
96 |
2 |
2 |
2 |
小孫 |
廣東 |
85 |
3 |
3 |
3 |
小丙 |
廣東 |
67 |
4 |
4 |
4 |
小紅 |
江蘇 |
98 |
1 |
1 |
1 |
小明 |
江蘇 |
98 |
1 |
1 |
2 |
小錢 |
江蘇 |
98 |
1 |
1 |
3 |
小乙 |
江蘇 |
81 |
4 |
2 |
4 |
小寅 |
江蘇 |
79 |
5 |
3 |
5 |
排名的數值上的特點:
2.2 使用方法
語法:
select *, rank() over(partition by 分組列 order by 排名列 desc)as 排名
from 成績表;
select *, dense_rank() over(partition by 分組列 order by 排名列 desc)as 排名
from 成績表;
select *, row_number() over(partition by 分組列 order by 排名列 desc)as 排名
from 成績表;
實例:
select *, rank() over(partition by 地區 order by 分數 desc)as 排名
from 成績表;
select *, dense_rank() over(partition by 地區 order by 分數 desc)as 排名
from 成績表;
select *, row_number() over(partition by 地區 order by 分數 desc)as 排名
from 成績表;
如果需要獲取指定排名或之前的數據,可配合子查詢實現。
select * from (
select *, rank() over(partition by 分組列 order by 排名列 desc)as 排名
from 成績表) as t
where 排名=N;
select * from (
select *, rank() over(partition by 分組列 order by 排名列 desc)as 排名
from 成績表) as t
where 排名<N;