一、通用函數和條件判斷語句 單引號出現的地方如下:1)字元串,例如:'hello'2)日期型,例如:'17-12月-80'3)to_char/to_date(日期,'YYYY-MM-DD HH24:MI:SS')雙引號出現的地方如下:1)列別名,例如:select ename "姓 名" from ...
一、通用函數和條件判斷語句
/*使用NULLIF(a,b)通用函數,在類型一致的情況下,如果a與b相同,返回NULL,否則返回a,比較10和10.0是否相同*/ select NULLIF(10,10.0) from dual; /*使用SQL99標準通用語法中的case表達式,將職位是分析員的,工資+1000;職位是經理的,工資+800;職位是其它的,工資+400 case 欄位 when 條件1 then 表達式1 when 條件2 then 表達式2 else 表達式n end 課後請參考<MySQL5.X的手冊>-12.2這個章節*/ select ename "姓名", job "職位", sal "漲前工資", case job when 'ANALYST' then sal + 1000 when 'MANAGER' then sal + 800 else sal + 400 end "漲後工資" from emp; /*使用oracle專用語法中的decode()函數,職位是分析員的,工資+1000;職位是經理的,工資+800;職位是其它的,工資+400 decode(欄位,條件1,表達式1,條件2,表達式2,...表達式n)*/ select ename "姓名", job "職位", sal "漲前工資", decode(job, 'ANALYST', sal + 1000, 'MANAGER', sal + 800, sal + 400) "漲後工資" from emp;
單引號出現的地方如下:
1)字元串,例如:'hello'
2)日期型,例如:'17-12月-80'
3)to_char/to_date(日期,'YYYY-MM-DD HH24:MI:SS')
雙引號出現的地方如下:
1)列別名,例如:select ename "姓 名" from emp
2)to_char/to_date(日期,'YYYY"年"MM"月"DD"日" HH24:MI:SS')單引號中的英文字元大小寫不敏感
二、多行函數
函數:oracle伺服器先事寫好的一段具有一定功能的程式片段,內置於oracle伺服器,供用戶調用。
單行函數:輸入一個參數,輸出一個結果,例如:upper('baidu.com')->BAIDU.COM
多行函數:輸入多個參數,或者是內部掃描多次,輸出一個結果,例如:count(*)->14
/*統計emp表中員工總人數*/ select count(*) from emp; *號適用於表欄位較少的情況下,如果欄位較多,掃描多間多,效率低,項目中提倡使用某一個非null唯一的欄位,通常是主鍵 /*統計公司有多少個不重覆的部門*/ select count(distinct deptno) from emp; /*統計有佣金的員工人數*/ select count(comm) from emp; 註意:今天這些多行函數,不統計NULL值 /*員工總工資,平均工資,四捨五入,保留小數點後0位*/ select sum(sal) "總工資", round(avg(sal), 0) "平均工資" from emp; /*查詢員工表中最高工資,最低工資*/ select max(sal) "最高工資", min(sal) "最低工資" from emp; /*入職最早,入職最晚員工*/ select max(hiredate) "最晚入職時間", min(hiredate) "最早入職時間" from emp; 多行函數:count/sum/avg/max/min /*按部門求出該部門平均工資,且平均工資取整數,採用截斷*/ select deptno "部門編號", trunc(avg(sal), 0) "部門平均工資" from emp group by deptno; /*查詢部門平均工資大於2000元的部門*/ select deptno "部門編號", trunc(avg(sal), 0) "部門平均工資" from emp group by deptno having trunc(avg(sal), 0) > 2000; /*按部門平均工資降序排列*/ select deptno "部門編號", trunc(avg(sal), 0) "部門平均工資" from emp group by deptno having trunc(avg(sal), 0) > 2000 order by 2 desc; /*除10號部門外,查詢部門平均工資大於2000元的部門,方式一【having deptno<>10】*/ select deptno, avg(sal) from emp group by deptno having deptno <> 10; /*除10號部門外,查詢部門平均工資大於2000元的部門,方式二【where deptno<>10】 提倡*/ select deptno, avg(sal) from emp where deptno <> 10 group by deptno; /*顯示部門平均工資的最大值*/ select max(avg(sal)) "部門平均工資的最大值" from emp group by deptno; /*思考:顯示部門平均工資的最大值和該部門編號?*/ select max(avg(sal)) "部門平均工資的最大值", deptno "部門編號" from emp group by deptno; 錯誤
group by 子句的細節:
1)在select子句中出現的非多行函數的所有列,【必須】出現在group by子句中
2)在group by子句中出現的所有列,【可出現可不現】在select子句中
where和having的區別:
where:
1)行過濾器
2)針對原始的記錄
3)跟在from後面
4)where可省
5)先執行
having:
1)組過濾器
2)針對分組後的記錄
3)跟在group by後面
4)having可省
5)後執行
oracle中綜合語法:
1)select子句-----必須
2)from子句-------必須,不知寫什麼表了,就寫dual(啞表)
3)where子句------可選
4)group by子句---可選
5)having子句-----可選
6)order by 子句--可選,如果出現列名,別名,表達式,欄位
三、多表查詢
/*員工表emp和部門表dept的笛卡爾集(笛卡爾集表=列數之和,行數之積,笛卡爾集表內中有些數據是不符合要求的)*/ select emp.ename, dept.dname from emp, dept; /*使用等值連接/內連接(只能使用=號),顯示員工的編號,姓名,部門名,使用表別名簡化*/ select emp.empno, emp.ename, dept.dname, dept.deptno from emp, dept where emp.deptno = dept.deptno; /*使用非等值連接(不能使用=號,其它符號可以,例如:>=,<=,<>,betwen and等),顯示員工的編號,姓名,月薪,工資級別*/ select e.empno, e.ename, e.sal, s.grade from emp e, salgrade s where e.sal between s.losal and s.hisal;
內連接查詢:只能查詢出符合條件的記錄
外連接查詢:既能查詢出符合條件的記錄,也能根據一方強行將另一個方查詢出來
使用外連接,按部門10,20,30,40號,統計各部門員工人數,要求顯示部門號,部門名,人數
部門號 部門名 人數
10 ACCOUNTING 3
20 RESEARCH 5
30 SALES 6
40 OPERATIONS 0
等值連接/非等值連接/內連接:只會查詢出多張表中,根據某個欄位匹配,符合條件的記錄,不符合條件的記錄是不會存在的
/*左外連接[是oracle專用的,不是SQL99規則]*/ select dept.deptno "部門號", dept.dname "部門名", count(emp.empno) "人數" from dept, emp where dept.deptno = emp.deptno(+) group by dept.deptno, dept.dname; /*右外連接*/ select dept.deptno "部門號", dept.dname "部門名", count(emp.empno) "人數" from dept, emp where emp.deptno(+) = dept.deptno group by dept.deptno, dept.dname; /*使用左外連接,按部門10,20,30,40號,統計各部門員工人數,要求顯示部門號,部門名,人數,且按人數降序排列*/ select dept.deptno "部門號", dept.dname "部門名", count(emp.empno) "人數" from dept, emp where dept.deptno = emp.deptno(+) group by dept.deptno, dept.dname order by 3 desc; /*使用自連接,顯示"SMITH的上級是FORD"這種格式*/ select users.ename || '的上級是' || boss.ename from emp users, emp boss where users.mgr = boss.empno; 只有13條記錄,不含有KING /*基於上述問題,將KING的上級是“”顯示出來*/ select users.ename || '的上級是' || boss.ename from emp users, emp boss where users.mgr = boss.empno(+); 14條記錄 註意:自連接也用到內連接和外連接
四、子查詢
子查詢的作用:查詢條件未知的事物
查詢條件已知的問題:例如:查詢工資為800的員工信息
查詢條件未知的問題:例如:查詢工資為20號部門平均工資的員工信息
一個條件未知的問題,可以分解為多個條件已知的問題
/*查詢工資比WARD高的員工信息*/ 第一:查詢WARD的工資? select sal from emp where ename = 'WARD'; 第二:查詢工資比1250高的員工信息? select * from emp where sal > 1250; 子查詢: select * from emp where sal > (select sal from emp where ename = 'WARD'); /*查詢部門名為'SALES'的員工信息(方式一:子查詢)*/ 第一:查詢部門名為'SALES'的編號? select deptno from dept where dname = 'SALES'; 第二:查詢部門號為30的員工信息? select * from emp where deptno = 30; 子查詢: select * from emp where deptno = (select deptno from dept where dname = 'SALES');
子查詢細節:
1)子查詢與父查詢可以針對同一張表
2)子查詢與父查詢可以針對不同張表
3) 子查詢與父查詢在傳統參數時,數量要相同
4) 子查詢與父查詢在傳統參數時,類型要相同
5) 子查詢與父查詢在傳統參數時,含義要相同
/*查詢部門名為'SALES'的員工信息(方式二:多表查詢)*/ select emp.* from dept, emp where (dept.deptno = emp.deptno) and (dept.dname = 'SALES'); /*查詢每個員工編號,姓名,部門名,工資等級(三表查詢,這三張表並無外健關聯)*/ select e.empno, e.ename, d.dname, s.grade from emp e, dept d, salgrade s where (e.deptno = d.deptno) and (e.sal between s.losal and s.hisal); /*查詢工資最低的員工信息(單行子查詢,使用=號)*/ 第一:查詢出工資最低是多少? select min(sal) from emp; 第二:查詢工資為800的員工信息? select * from emp where sal = 800; 子查詢: select * from emp where sal = (select min(sal) from emp); /*查詢部門名為'ACCOUNTING'或'SALES'的員工信息(多行子查詢,使用in關鍵字)*/ 第一:查詢部門名為'ACCOUNTING'或'SALES'的部門編號? select deptno from dept where dname in ('ACCOUNTING','SALES'); 第二:查詢部門號為10或30號的員工信息? select * from emp where deptno in (10,30); 子查詢: select * from emp where deptno in (select deptno from dept where dname in ('ACCOUNTING', 'SALES')); /*查詢工資比20號部門【任意any】一個員工工資【低<】的員工信息(多行子查詢,使用any關鍵字)*/ 第一:查詢20號部門的所有工資? select sal from emp where deptno = 20; 第二:查詢工資比(800,2975,3000,1100,3000)任意一個低的員工信息? select * from emp where sal < any (800,2975,3000,1100,3000); 在oracle看來,<any就等於<集合中最大的那個值 子查詢: select * from emp where sal < any (select sal from emp where deptno = 20); /*查詢工資比30號部門【所有all】員工【低<】的員工信息(多行子查詢,使用all關鍵字)*/ 第一:查詢出30部門所有員工的工資? select sal from emp where deptno = 30; 第二:查詢工資比(1600,1250,1250,2850,1500,950)中所有的工資都低的員工信息? select * from emp where sal <all (1600,1250,1250,2850,1500,950); 子查詢: select * from emp where sal < all (select sal from emp where deptno = 30);
註意:不容易理解的幾個概念:
單行函數:輸入一個參數,輸出一個結果
多行函數:掃描多個參數,輸出一個結果
單行子查詢:子查詢只會返回一個結果,例如:800,父查詢用=、<>、>=、<=這些符號來比較
多行子查詢:子查詢會返回多於一個結果,例如:30,20,父查詢用in、any、all這些符號來比較
當多表查詢,子查詢同時能解決問題時,按如下優先方案選擇:
多表查詢-->子查詢
註意:上述結果不是說多表查詢可以替代子查詢,某些情況下,只能用子查詢解決,例如:oracle分頁
五、集合查詢
/*使用並集運算,查詢20號部門或30號部門的員工信息*/ select * from emp where deptno = 20 union select * from emp where deptno = 30; 註意: union:二個集合中,如果都有相同的,取其一 union all:二個集合中,如果都有相同的,都取 /*使用set time/timing on,打開時間的開關*/ set time on; set time off; /*使用set tim/timing off,關閉時間的開關*/ set timing on; set timint off; /*使用交集運算[intersect],查詢工資在1000-2000和1500-2500之間的員工信息(方式一)*/ select * from emp where sal between 1000 and 2000 intersect select * from emp where sal between 1500 and 2500; /*用where行過濾,查詢工資在1000-2000和1500-2500之間的員工信息(方式二)*/ select * from emp where (sal between 1000 and 2000) and (sal between 1500 and 2500); /*使用差集運算[minus],查詢工資在1000-2000,但不在1500-2500之間的員工信息(方式一)*/ select * from emp where sal between 1000 and 2000 minus select * from emp where sal between 1500 and 2500; /*使用where行過濾,查詢工資在1000-2000,但不在1500-2500之間的員工信息(方式二)*/ select * from emp where (sal between 1000 and 2000) and (sal not between 1500 and 2500); 集合查詢的細節: /*1)集合操作時,必須確保集合列數是相等*/ select empno, ename, sal, comm from emp where deptno = 20 union select empno, ename, sal from emp where deptno = 30; 錯,因為列數不一樣 /*2)集合操作時,必須確保集合列類型對應相同*/ select empno, ename, sal, comm from emp where deptno = 20 union select empno, ename, sal, hiredate from emp where deptno = 30; 錯,因為集合類型不一樣 /*3)A union B union C = C union B union A*/ select * from emp where deptno = 10 union select * from emp where deptno = 20 union select * from emp where deptno = 30; /*4)當多個集合操作時,結果的列名由第一個集合列名決定*/ select empno "編號", ename "姓名", sal "薪水" from emp where deptno = 20 union select empno, ename, sal from emp where deptno = 10;
總結:當多表查詢,子查詢,集合查詢都能完成同樣任務時,按如下優化方案選擇:多表查詢->子查詢->集合查詢
六、Oracle的分頁
介紹Oracle之前,我們先介紹一些MySql分頁和Hibernate分頁,代碼如下:
回顧mysql分頁 用limit關鍵字 /*查詢users表中前二條記錄*/ select * from users limit 0,2 或 select * from users limit 2; 0表示第一條記錄的索引號,索引號從0開始 2表示最多選取二個記錄 /*查詢出users前三條記錄*/ select * from users limit 0,3 或 select * from users limit 3 /*查詢出users第2條到第4條記錄*/ select * from users limit 1,3; 回顧hibernate分頁API Query.setFirstResult(0); Query.setMaxResult(3);
並且想要瞭解Oracle的分頁之前,我們還需要知道rownum概念,什麼是rownum,有何特點?
1)rownum是oracle專用的關健字
2)rownum與表在一起,表亡它亡,表在它在
3)rownum在預設情況下,從表中是查不出來的
4)只有在select子句中,明確寫出rownum才能顯示出來
5)rownum是number類型,且唯一連續
6)rownum最小值是1,最大值與你的記錄條數相同
7)rownum也能參與關係運算
* rownum = 1 有值
* rownum < 5 有值
* rownum <=5 有值
* rownum > 2 無值
* rownum >=2 無值
* rownum <>2 有值 與 rownum < 2 相同
* rownum = 2 無值
8)基於rownum的特性,我們通常rownum只用於<或<=關係運算
/*顯示emp表中3-8條記錄(方式一:使用集合減運算)*/ select rownum "偽列", emp.* from emp where rownum <= 8 minus select rownum, emp.* from emp where rownum <= 2; /*顯示emp表中3-8條記錄(方式二:使用子查詢,在from子句中使用,重點)*/ select xx.* from (select rownum ids, emp.* from emp where rownum <= 8) xx where ids >= 2; 註意:在子查詢中的別名,不可加""引號 /*顯示emp表中5-9條記錄*/ select yy.* from (select rownum ids, emp.* from emp where rownum <= 9) yy where ids >= 5; 註意:在項目中,from後臺可能有真實表名,也可能用子查詢看作的表名,同時真實表和子查詢看作的表要做連接查詢
七、創建表和約束
/*回顧MySQL創建表語句users(id整型/name字元串/birthday日期型,預設今天)*/ drop table if exists users; create table if not exists users( id int(5) auto_increment primary key, name varchar(4) not null, birthday date default '2015-4-27' ); /*使用oracleSQL,創建用戶表users(id整型/name字元串/birthday日期/sal整型,預設今天)*/ create table users( id number(5) primary key, name varchar2(8) not null unique, sal number(6,2) not null, birthday date default sysdate ); /*進入回收站*/ drop table users; /*查詢回收站中的對象*/ show recyclebin; /*閃回,即將回收站還原*/ flashback table 表名 to before drop; flashback table 表名 to before drop rename to 新表名; /*徹底刪除users表*/ drop table users purge; /*清空回收站*/ purge recyclebin; /*測試如下類型*/ (1)number(5): insert into users(id,name,sal) values(1,'A',6666.66); insert into users(id,name,sal) values(11,'AA',6666.66); insert into users(id,name,sal) values(111,'AAA',6666.66); insert into users(id,name,sal) values(1111,'AAAA',6666.66); insert into users(id,name,sal) values(99999,'AAAAA',6666.66); insert into users(id,name,sal) values(100000,'AAAAAA',6666.66); 錯 5表示最多存99999 (2)number(6,2): col sal for 9999.99 insert into users(id,name,sal) values(1,'A',6.66); insert into users(id,name,sal) values(11,'AA',66.666); insert into users(id,name,sal) values(111,'AAA',666.6666); insert into users(id,name,sal) values(1111,'AAAA',6666.66666); insert into users(id,name,sal) values(11111,'AAAAA',66666.666666);錯 number(6,2) 其中2表示最多顯示2位小數,採用四捨五入,不足位數補0,同時要設置col ... for ... 其中6表示小數+整數不多於6位 其中整數位數不得多於4位,可以等於4位 (3)varchar2(8): insert into users(id,name,sal) values(1,'A',7777.77); insert into users(id,name,sal) values(2,'AA',7777.77); insert into users(id,name,sal) values(3,'AAA',7777.77); insert into users(id,name,sal) values(4,'AAAA',7777.77); insert into users(id,name,sal) values(5,'AAAAA',7777.77); insert into users(id,name,sal) values(6,'AAAAAA