Oracle數據庫:單行函數、組函數、分組、rowid和rownum


學習目標

在這裏插入圖片描述

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

rowidrownum都是僞列(表中沒有該字段,但是可以查詢到)。

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;

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章