文章目錄
學習目標
1、單行函數
根據函數的返回結果,我們將函數分爲單行函數和多行函數
- 單行函數:一條記錄返回一個結果
- 多行函數、組函數、聚合函數(重點):多條記錄返回一個結果(重點)
1.1、日期函數
-
sysdate/current_date 以date類型返回當前的日期
-
add_months(d,x) 返回加上x月後的日期d的值
-
**last_day(d)**返回所在月的最後一天
-
months_between(date1,date2) 返回date1和date2之間月的數目
-
next_day(sysdate,‘星期一’) 返回下週星期一的日期
1.1.1、當前時間
- sysdate
- current_date
-- 當前時間
select sysdate from dual;
select current_date from dual;
1.1.2、加減時間
-- 加減日期
-- 2天以後是幾號
select sysdate+2 from dual;
-- 所有員工入職的3天后是幾號
select ename 姓名,hiredate 入職日期, hiredate+3 入職三天後的日期 from emp ;
1.1.3、修改月份
- add_month( )
--add_months(hiredate,3) 查詢所有員工的試用期期到期(轉正的日期) 3個月試用期
select ename,empno,hiredate 入職日期,add_months(hiredate,3) from emp;
1.1.4、月份之差
- months_between
-- 查詢所有員工到目前爲止一共工作了幾個月
select months_between(sysdate,hiredate) 入職的月數 from emp;
1.1.5、月的最後一天
- last_day()
-- 查詢當前月的最後一天
select last_day(sysdate) from dual;
1.5.6、下一個星期X的時間
- next-day
-- 下一個星期三是幾號
select next_day(sysdate,'星期二') from dual;
1.2、日期和字符串的轉化
- to_char()
- to_date()
1.2.1、to_char()
-- 將日期轉爲特定格式的字符串 to_char
select to_char(sysdate,'yyyy"年"mm"月"dd"號"')from dual;
select to_char(sysdate,'yyyy-mm-dd hh24:mi;ss')from dual;
select to_char(sysdate,'yyyy')from dual;
1.2.2、to_date()
--to_date(日期字符串,日期轉換模板) 'yyyy-mm-dd hh24:mi:ss'
select to_date('2020.08.12 12:25:56','yyyy-mm-dd hh24:mi:ss') 今天 from dual;
1.2.3、nvl()函數、decode()函數
--nvl(string1,string2) 如果string1爲null,則結果爲string2的值
select ename, nvl(null,0) from emp;
--給每個部門後後面添加一個僞列,如果10部門,僞列顯示爲十,二十,三十...
select deptno,dname,decode(deptno,10,'十',20,'二十',30,'三十','四十') from dept;
--case when then else end
select ename,
sal,
deptno,
(case deptno
when 10 then
sal * 1.1
when 20 then
sal * 1.08
when 30 then
sal * 1.15
else
sal * 1.2
end) raisesal
from emp;
2、組函數
組函數|多行函數|聚合函數即多條記錄返回一個結果。
- count();統計表中記錄的個數
- max()|min():最大值、最小值
- sum():求和
- avg():求平均值
注意:
- 組函數僅在選擇列表和
having
語句中有效; - 如果出現組函數,
select
後面只能跟組函數或分組字段; - 組函數中可以使用
distinct
關鍵字去重; - 組函數不能使用在
where
後面,但是可以使用在having
後面; - 計算組函數時null不參與運算;
- 組函數不能與非分組字段一起使用,組函數只能與組函數和分組字段(即group by後面的字段)一起使用。
-- 統計一下一共有多少個員工
select count(ename) from emp;
select count(1) from emp;--使用僞列也可以
-- 統計一共有幾個部門
select count(deptno) from dept;
-- 統計有員工存在的部門總數,在組函數中可以去重
select count(distinct deptno) from emp;
-- 統計20部門一共有多少人
select count(ename) from emp where deptno = 20;
-- 計算本公司每個月一共要在工資上花費多少錢
select sum(sal) from emp;
-- 計算20部門每個月的工資花銷
select sum(sal) from emp where deptno = 20;
-- 查詢本公司的最高工資和最低工資
select max(sal) 最高工資,min(sal) 最低工資 from emp;
--查看30部門的最高工資和最低工資
select max(sal) 最高工資,min(sal) 最低工資 from emp where deptno = 30;
-- 計算出所有員工的獎金總和,null不參與運算
select sum(comm) 獎金總和 from emp;
-- 統計有獎金的員工有幾個
select count(comm) 有獎金的員工個數 from emp where comm is not null;
--查詢 最高薪水的員工姓名, 及薪水
select ename 姓名,sal 薪水 from emp where sal = (select max(sal) from emp);
-- 查詢工資低於平均工資的員工編號,姓名及工資
select deptno 員工編號,ename 姓名,sal 工資 from emp where sal < (select avg(sal) from emp);
3、分組
- 使用關鍵字group by對符合條件的記錄進一步分組;
- 使用關鍵字having對每個組進行進一步篩選。
語法:
select distinct * | 字段 | 表達式 | 函數 as 別名
from 表 表別名
where 過濾行記錄條件
group by 分組字段列表
having 過濾組
order by 字段列表 asc | desc
執行流程:from–>where–>group by -->having–>select–>order by
注意:
-
select後出現分組函數就不可以使用非分組字段,但是可以使用group by後的分組字段;
-
group by的分組字段可以不出現在select後,但是select後除組函數外其他字段必須出現在group by之後。
-
where之後進行行過濾,且不可以使用組函數;having進行組過濾,having後只能使用組函數和分組字段。
-
having後使用組函數時不可以嵌套使用,但是select後可以嵌套使用組函數。
不使用分組,但是可以達到分組的效果:
-- 查出比本部門平均工資高的員工信息
select *
from emp e1
where sal > (select avg(sal) from emp e2 where e2.deptno = e1.deptno);
/*解析|執行流程:依次從e1中拿出一條語句和e2中所有的數據比較(e2.deptno = e1.deptno),比較完畢後得到了是當前部門的多有記錄(即達到了分組的效果),然後對該組數據取平均值。
*/
-- 找出20部門和30部門的最高工資
select max(sal),deptno from emp group by deptno having deptno in(20,30);-- 先分組,後過濾
select max(sal),deptno from emp where deptno in(20,30) group by deptno;-- 先過濾,後分組
-- 求出每個部門的平均工資
select avg(sal),deptno from emp group by deptno;
-- 求出每個部門員工工資高於1000的的平均工資
select avg(sal), deptno from emp where sal > 1000 group by deptno
-- 求出10和20部門的哪些工資高於1000的員工的平均工資
select avg(sal), deptno
from emp
where sal > 1000
group by deptno
having deptno in(10, 20); --先分組後判斷
select avg(sal), deptno
from emp
where sal > 1000
and deptno in (10, 20)
group by deptno; --先判斷後分組
-- 找出每個部門的最高工資
select max(sal),deptno from emp group by deptno;
-- 求出平均工資高於2000的部門編號和平均工資
select avg(sal),deptno from emp group by deptno having avg(sal) > 2000;
--按 崗位查詢 平均工資,且平均工資大於2000的崗位
select job from emp group by job having avg(sal) >2000;
--先求出所有崗位的平均薪資和崗位,再判斷平均薪資是否>2000
select job
from (select avg(sal) avg_sal, job from emp group by job)
where avg_sal > 2000;
--或者
select avg(sal), deptno
from emp
group by deptno
having avg(sal) = (select min(avg(sal)) from emp group by deptno);
錯誤實例:
--注意:以下寫法會報“分組函數嵌套太深錯誤”,無法使用
select avg(sal) from emp group by deptno having min(avg(sal));
4、行轉列
準備工作:
/*
id name course score
1 張三 語文 81
2 張三 數學 75
3 李四 語文 81
4 李四 數學 90
5 王五 語文 81
6 王五 數學 100
7 王五 英語 90
create table tb_student(
id number(4) ,
name varchar2(20),
course varchar2(20),
score number(5,2)
);
insert into tb_student values(1,'張三','語文',81);
insert into tb_student values(2,'張三','數學',75);
insert into tb_student values(3,'李四','語文',81);
insert into tb_student values(4,'李四','數學',90);
insert into tb_student values(5,'王五','語文',81);
insert into tb_student values(6,'王五','數學',100);
insert into tb_student values(7,'王五','英語',90);
commit;
drop table tb_student cascade constraints;
*/
簡單操作實例:
--查詢每門課都大於80分的學生姓名
-- select name from tb_student where 學生課程數 = 3 and 最低分數 > 80
--1.查看最大課程數
select count(distinct course) from tb_student;
--2.查看每個學生的課程數(用到了分組)
select count(course) from tb_student group by name;
--3.查看每個學生的最低分數
select min(score) from tb_student group by name;
--合併得最終結果
select name
from tb_student
group by name
having count(course) = (select count(distinct course) from tb_student) and min(score) > 80
原生效果:
--1.查看錶結構
select * from tb_student;
--2.使用decoude()函數組合成新的表頭展示形式
select name,
decode(course, '語文', score,null) 語文,
decode(course, '數學', score) 數學,
decode(course, '英語', score) 英語
from tb_student ;
實現行轉列效果:
-- 分組後select後只能使用分組字段和組函數
--在每個分組中,對decode函數生成的僞列取最大值,達到去重(合併)的效果
--3.去除無效的數字
select name,
max(decode(course, '語文', score,null)) 語文,
min(decode(course, '數學', score)) 數學,
min(decode(course, '英語', score)) 英語
from tb_student group by name;
5、rowid和rownum
rowid和rownum都是僞列(表中沒有該字段,但是可以查詢到)。
5.1、rowid
rowid 相當於對象的地址,區分表中的數據,是記錄的唯一(和主鍵的地位一樣),在數據插入表中時就存在。
作用:
- 可以對相同數據做去重(沒有主鍵的表)。
- 在沒有主鍵的情況下仍可以唯一確定一條記錄。
- 如果在select語句後沒有給出rowid和rownum字段|僞列,仍可以正常使用。
select deptno,dname,loc,rowid from dept;
唯一確定一條數據:
select *
from emp
where rowid = (select rowid from emp where empno = 7369);
使用rowid去重
注:表中沒有主鍵
select * from tb_student;
去重:
--拿到rowid唯一值
select max(rowid) from tb_student group by id;
--去重
delete from tb_student
where rowid not in (select max(rowid) from tb_student group by id);
5.2、rownum
- rownum是僞列,是結果集的序號,只要有select就有結果集就有rownum,每一套結果集都有自己的rownum
- 規律: 把已確定了的結果集中的數據從第一個開始設置rownum,從1開始,依次+1;
- 優點: 有規律可循,結果集的序號是數字,可以進行判斷;
- 作用:可以使用rownum對結果集進行分頁並顯。
select empno,ename,sal,rownum from emp;
5.2.1、使用rownum實現分頁
-- 查詢前五條數據
select empno,ename,sal,rownum from emp where rownum>= 1 and rownum <=5;
--或者
select empno,ename,sal,rownum from emp where rownum <=5;
以下方式(分頁的數據不是從1開始顯示的)沒有語法錯誤但是查詢不到任何數據:
select empno,ename,sal,rownum from emp where rownum > 5;
原因:
- rownum是對一個結果集中的數據進行編號,上述where後每次拿到rownum都爲1,不能滿足rownum>5的條件。
解決方案:
- 使用select語句嵌套後再使用
- 若where中使用內部(子查詢)rownum時要使用別名,如果直接寫rownum,被認爲是外部select語句中的。
--查詢6~10之間的數據
select empno, ename, sal, rn
from (select empno, ename, sal, rownum rn from emp)
where rn > 5
and rn <= 10;
5.2.1、rownum排序彙總的亂序問題
-
如果存在排序,rownum的序號可能出現問題(亂號)
-
如果根據主鍵進行order by,則先排序再rownum,如果根據其他字段排序,一般會先rownum,再order by
--根據主鍵進行排序時rownum不會亂
select empno,ename,sal,rownum from emp order by empno;
--根據非主鍵排序時rownum會出現亂的情況
select empno,ename,sal,rownum from emp order by deptno;
解決方案:
- 在排序後外層再嵌套一個select,讓系統對rownum僞列進行重新排序
select empno, ename, sal, rownum
from (select empno, ename, sal, rownum from emp order by deptno);
--對emp表按工資進行升序排列,然後取rownum爲6~10的數據
select empno, ename, sal from emp order by sal asc;--中間步驟1
select empno, ename, sal, rownum
from (select empno, ename, sal from emp order by sal asc); --中間步驟2
--結果
select empno, ename, sal, rn
from (select empno, ename, sal, rownum rn
from (select empno, ename, sal from emp order by sal asc))
where rn > 5
and rn <= 10;
習題:
--按照工資降序排序 查詢第三頁的數據, 每一頁顯示4條記錄
select empno, ename, deptno, rownum from emp order by sal asc; --中間步驟1
select empno, ename, deptno, rownum rnum
from (select empno, ename, deptno, rownum from emp order by sal asc); --中間步驟2
--結果
select empno, ename, deptno, rnum
from (select empno, ename, deptno, rownum rnum
from (select empno, ename, deptno, rownum from emp order by sal asc))
where rnum > 4 * 2
and rnum <= 12;