1.基本SQL select語(yǔ)句
1.1 sqlplus登陸
1.2sqlplus 的基本操作
1.3基本select語(yǔ)句
1.4SQL語(yǔ)句使用注意事項(xiàng)
1.5算數(shù)運(yùn)算 +-*/
1.6NULL值
1.7 連接符
1.8SQL和sqlplus2.過(guò)濾和排序數(shù)據(jù)
2.1where條件過(guò)濾
2.2order by3.單行函數(shù)
3.1字符函數(shù)
3.2數(shù)值函數(shù)
3.3時(shí)間函數(shù)
3.4日期函數(shù)
3.5轉(zhuǎn)換函數(shù)
3.6通用函數(shù)
3.7條件表達(dá)式4.分組函數(shù)
4.1分組函數(shù)
4.2分組數(shù)據(jù)
4.3HAVING
4.4group by 的增強(qiáng)(擴(kuò)展知識(shí))5.多表查詢
5.1等值鏈接
5.2不等值鏈接
5.3外鏈接
5.4自連接
5.5層次查詢6.子查詢
6.1定義子查詢 需要注意的問(wèn)題
6.2主、子查詢?cè)诓煌黹g進(jìn)行
6.3在主查詢的where、select、having、from 放置子查詢
6.4在from后面放置子查詢
6.5一般先執(zhí)行子查詢,再執(zhí)行主查詢
6.6一般不在子查詢中使用Order by(練習(xí))
6.7 單行子查詢只能使用單行操作符;多行子查詢只能使用多行操作符
6.8子查詢中Null7.集合運(yùn)算
7.1集合運(yùn)算符
7.2集合運(yùn)算需要注意的問(wèn)題
1.基本SQL select語(yǔ)句
1.1 sqlplus登陸
sqlplus 賬號(hào)/密碼
1.2sqlplus 的基本操作
顯示當(dāng)前用戶:SQL>show user;
查看當(dāng)前用戶下的表:
SQL>select * from tab;
tab:數(shù)據(jù)字典(記錄數(shù)據(jù)庫(kù)和應(yīng)用程序源數(shù)據(jù)的目錄),包含當(dāng)前用戶下的表
查看表的結(jié)構(gòu):SQL>desc emp;(desc -> description描述)
設(shè)置行寬:set linesize 120;
設(shè)置頁(yè)面:
set pagesize 100;
或者將上述行寬和頁(yè)面寫(xiě)入如下配置文件,永久配置
(Oracle下載目錄)\product\11.2.0\dbhome_1\sqlplus\admin\glogin.sql
設(shè)置員工名列寬:col ename for a20(a表示字符串)
設(shè)置薪水列為4個(gè)數(shù)字:col sal for 9999(一個(gè)9表示一個(gè)數(shù)字)
1.3基本select語(yǔ)句
其語(yǔ)法格式為:
SELECT *|{[DISTINCT]column|expression[alias],...}
FROM table;
查詢所有員工的所有記錄:
SQL>select * from emp;
(效果等同于)
SQL>select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp;
查詢員工號(hào)、姓名、薪水:
SQL>select empno,ename,sal from emp;
增加年薪:
SQL>select empno,ename,sal,sal*12
from emp;
"/"執(zhí)行上一條成功執(zhí)行的SQL語(yǔ)句
修改上一條SQL語(yǔ)句
- 用c命令來(lái)修改(c = change)
默認(rèn),光標(biāo)閃爍位置指向上一條SQL語(yǔ)句的第一行,輸入2則定位到第二行
c /錯(cuò)誤關(guān)鍵字/正確關(guān)鍵字
使用"/"來(lái)執(zhí)行修改過(guò)的SQL語(yǔ)句
例如:錯(cuò)誤輸入了:
SQL> select empno,ename,sal,sal*12
form emp;("from"書(shū)寫(xiě)錯(cuò)誤,該錯(cuò)誤位于整條SQL語(yǔ)句的第二行)
(1) 輸入:2 終端提示:2 * from emp
(2) 輸入:c /form/from 終端提示2 * from emp(意為改正后的sql語(yǔ)句樣子)
(3)輸入:/
使用ed命令來(lái)修改 edit
ed 彈出系統(tǒng)默認(rèn)的文本編輯器(如記事本)
修改、保存、退出、執(zhí)行"/"別名:as
SQL>select empno as "員工號(hào)",ename "姓名",sal "月薪",sal * 12 年薪
from emp;
關(guān)鍵字as寫(xiě)與不寫(xiě)沒(méi)有區(qū)別
“”有與沒(méi)有取決于別名中是否有空格或者關(guān)鍵字
- DISTINCT 關(guān)鍵字
“DISTINCT”關(guān)鍵字,重復(fù)記錄只取一次
SQL>select deptno from emp;----> SQL> select DISTINCT deptno from emp;
SQL>select job from emp;----> SQL> select DISTINCT job from emp;
SQL>select DISTINCT deptno,job from emp;會(huì)發(fā)現(xiàn)沒(méi)有行減少,因?yàn)閐eptno不重復(fù)。因此得出,distinct作用于后面的所有列
1.4SQL語(yǔ)句使用注意事項(xiàng)
- SQL語(yǔ)言大小寫(xiě)不敏感
- SQL可以寫(xiě)在一行或者多行
- 關(guān)鍵字不能被縮寫(xiě)也不能分行
- 各字句一般要分行寫(xiě)
- 使用縮進(jìn)提高語(yǔ)句的可讀性
1.5算數(shù)運(yùn)算 +-*/
- 乘除優(yōu)先級(jí)高于加減
- 優(yōu)先級(jí)相同時(shí),按照從左到右運(yùn)算
- 可以使用括號(hào)改變優(yōu)先級(jí)
查詢:?jiǎn)T工號(hào)、姓名、月薪、年薪、獎(jiǎng)金、年收入
SQL>select deptno,ename,sal ,sal * 12 ,comm,comm+sal*12 from emp;
結(jié)果不正確。沒(méi)有獎(jiǎng)金的員工,年收入不正確
需注意,在程序開(kāi)發(fā)過(guò)程中,數(shù)據(jù)是核心。程序再正確也沒(méi)有用,必須保證數(shù)據(jù)不能丟,且正確。對(duì)于上面的結(jié)果,有對(duì)有錯(cuò)的情況是最危險(xiǎn)的。
1.6NULL值
※NULL值問(wèn)題:1.包含NULL值得表達(dá)式都為空。2.NULL != NULL
解決:慮空函數(shù):nvl(a,b)如果a為NULL,函數(shù)返回b,所以:sal * 12 + nvl(comm,0)
年收入。
查詢獎(jiǎng)金為NULL的員工信息:
SQL>select * from emp where comm = NULL(SQL中不使用==)
在SQL中,判斷一值是否等于另外一值不用"="和"!="而使用is和is not
SQL>select * from emp where comm is NULL;(is not)
- 空值是無(wú)效的,未指定的,未知的或不可預(yù)知的值
- 空值不是空格或者0
1.7 連接符
Oracle 中定義了一個(gè)連接符"||"用來(lái)連接字符串
顯示"xxx是一個(gè)xxx"怎么顯示呢?
SQL>select ename ||'is a'||'job' from emp;
但是如果顯示一個(gè)"hello world"應(yīng)該怎么顯示呢?
- 使用concat函數(shù)來(lái)實(shí)現(xiàn):
SQL>select concat('hello','world') from ????
這兩個(gè)字符串不是任何一個(gè)表的內(nèi)容,在Oracle中,定義一張"偽表"dual用來(lái)滿足SQL99語(yǔ)法(ANSI)
語(yǔ)法規(guī)定:select后 必須接 from
但是,concat函數(shù)最多只能有兩個(gè)參數(shù),再多的參數(shù)需要用連接符"||"來(lái)完成拼接!
1.8SQL和sqlplus
我們已經(jīng)學(xué)習(xí)使用了select,應(yīng)該知道還有update,delete,insert,create...
同時(shí),我們學(xué)習(xí)了ed,c,set,col,desc...
SQL->語(yǔ)言,關(guān)鍵字不能縮寫(xiě)
sqlplus->Oracle提供的工具,可在里面執(zhí)行SQL語(yǔ)句,它配有自己的命令(ed,c,set,col)特點(diǎn)是縮寫(xiě)關(guān)鍵字
SQL
- 一種語(yǔ)言
- ANSI標(biāo)準(zhǔn)
- 關(guān)鍵字不能縮寫(xiě)
- 使用語(yǔ)句控制數(shù)據(jù)庫(kù)中的表的定義信息和表中的數(shù)據(jù)
SQL *Plus
- 一種環(huán)境
- Oracle的特性之一
- 關(guān)鍵字可以縮寫(xiě)
- 命令不能改變數(shù)據(jù)庫(kù)中的數(shù)據(jù)的值
- 集中運(yùn)行
2.過(guò)濾和排序數(shù)據(jù)
2.1where條件過(guò)濾
2.1.1日期格式
查詢10號(hào)部門的員工信息
SQL>select * from emp where deptno=10
查詢"KING"的信息
SQL>select * from emp where ENAME='KiNg';未選定行
注意:字符串大小寫(xiě)敏感
SQL>select * from emp where ENAME='KING';則正確
查詢?nèi)肼毴掌跒?981年11月17日的員工
SQL>select * from emp where hiredate='1981-11-17'可以嗎?
參看,SQL>select sysdate from dual 查看系統(tǒng)當(dāng)前的日期(注意其格式)
SQL>select * from emp where hiredate='17-11月-81
現(xiàn)在,我們想修改日期格式顯示方式
獲取系統(tǒng)當(dāng)前日期格式:
SQL>select * from v$nls_parameters;(數(shù)據(jù)字典,類似于tab)
設(shè)置列寬度,SQL>col parameter for a30;
修改日期格式:
SQL>alter session set NLS_DATE_FORMAT= 'yyyy-mm-dd';
再次查詢:
SQL>select * from emp where hiredate='1981-11-17';
SQL>alter session set NLS_DATE_FORMAT= 'yyyy-mm-dd hh24:mi:ss'; 顯示帶有時(shí)間的日期
SQL>select sysdate from dual; 再次查看系統(tǒng)時(shí)間
改回系統(tǒng)默認(rèn)格式:SQL>alter session set NLS_DATE_FORMAT='DD-MON-RR';
1. 字符和日期要包含在單引號(hào)中
2. 字符大小寫(xiě)敏感,日期格式敏感
3. 默認(rèn)的日期格式是DD-MON-RR
2.1.2比較運(yùn)算
- 普通比較運(yùn)算
= 等于(不是==) > 大于
>= 大于等于 < 小于
<= 小于等于 <>不等于(也可以是!=)
- BETWEEN...AND... 介于兩值之間
查詢工資在1000-2000之間的員工:
使用比較運(yùn)算符
SQL>select * from emp where sal >= 1000 and sal < 2000;(注意第二個(gè)sal不能省略)
用between and:
SQL>select * from emp where sal between 1000 and 2000;
注意:1.包含邊界 2.小值在前,大值在后。(對(duì)于日期也是如此)
查詢81年2月至82年2月入職的員工信息:
SQL>select * from emp where hiredate between '1-2月-81' and '30-1月-82';
- IN:在集合中。(NOT IN 不在集合中)
查詢部門號(hào)為10和20的員工信息
1.SQL>select * from emp where deptno=10 or deptno=20;
2.SQL>select * from emp where deptno IN (10,20);
SQL>select * from emp where deptno not in (10,20);
但是,如果是...not in(10,20,NULL)可不可以呢?
NULL空值:如果結(jié)果中含有NULL,不能使用not in操作符,但可以使用in操作符
- like 模糊查詢‘%’匹配多個(gè)字符。‘_’匹配一個(gè)字符
查詢名字以S開(kāi)頭的員工:
SQL>select * from emp where ename like 'S%';
查詢名字是4個(gè)字的員工:
SQL>select * from emp where ename like '____';
查詢名字中包含_的員工
SQL>select * from emp where ename like '%\_% escape '\';
2.1.3邏輯運(yùn)算
AND 邏輯并
OR 邏輯或
NOT 邏輯非
如果...where 表達(dá)式1 and 表達(dá)式2;
...where 表達(dá)式2 and 表達(dá)式1;
這兩句SQL語(yǔ)句功能一樣嗎?效率一樣嗎?
SQL 優(yōu)化
SQL在解析where的時(shí)候,是從右到左解析的。
所以
and時(shí)應(yīng)該將易假的值放在右側(cè)
or時(shí)應(yīng)該將易真的值放在右邊
2.2order by
- 使用ORDER BY子句排序
- ASC(ascend):升序。默認(rèn)采用升序方式
- DESC(descend)降序。
- ORDER BY 子句在SELECT語(yǔ)句的結(jié)尾
SELECT last_name,job_id,department_id,hire_date
FROM employees
ORDER BY hire_date;
SQL>select * from emp order by deptno,sal ;
order by后與多列時(shí),列名之間用逗號(hào)隔分,order by會(huì)同時(shí)作用于多列。上例的運(yùn)行結(jié)果會(huì)在同一個(gè)部門內(nèi)升序,部門間再升序
查詢員工信息,按獎(jiǎng)金由高到低排序:
SQL>select * from emp order byu comm desc
結(jié)果前面的值是NULL,數(shù)據(jù)在后面,如果是一個(gè)100頁(yè)的報(bào)表,這樣的顯示肯定不正確。較為人性化的顯示應(yīng)該將空值放在最后,即
SQL>select * from emp order by comm desc nulls last(注意是nulls而不是null)
排序的規(guī)則
- 可以按照select語(yǔ)句中的列名排序
- 可以按照別名列名排序
- 可以按照select 語(yǔ)句中的列名的順序值排序
- 如果要按照多列進(jìn)行排序,則規(guī)則是先按照第一列排序,如果向彤彤,則按照第二列排序,以此類推
3.單行函數(shù)
單行函數(shù):只對(duì)一行進(jìn)行變換,產(chǎn)生一個(gè)結(jié)果。函數(shù)可以沒(méi)有參數(shù),但必須要有返回值。如:concat、nvl
- 操作數(shù)據(jù)對(duì)象
- 接受參數(shù)返回一個(gè)結(jié)果
- 只對(duì)一行進(jìn)行變換
- 每行返回一個(gè)結(jié)果
- 可以轉(zhuǎn)換數(shù)據(jù)類型
- 可以嵌套
- 參數(shù)可以是一列或者一個(gè)值
3.1字符函數(shù)
操作對(duì)象是字符串
大致可以分為兩大類,一類是大小寫(xiě)控制函數(shù),主要有l(wèi)ower、upper、initcap
SQL>select lower('Hello,WorLD') 轉(zhuǎn)小寫(xiě),upper('Hello,WorLD') 轉(zhuǎn)大寫(xiě),initcap('Hello,WorLD') 首字母大寫(xiě) from dual
另一類是字符控制函數(shù),有CONCAT、SUBSTR、LENGTH/LENGTHB、INSTR、LPAD|RPAD、TRIM、REPLACE
substr(a,b):從a中,第b位開(kāi)始取(計(jì)數(shù)從1開(kāi)始),取到結(jié)尾
SQL>select substr('hello world',3) from dual;
substr(a,b,c),從a中第b位開(kāi)始,向右取c位
SQL>select substr('hello world',3,5) from dual;
length:字符數(shù),lengthb字節(jié)數(shù)
SQL>select length('hello world') 字符數(shù),lengthb('hello world') 字節(jié)數(shù) from dual;注意中英文差異
instr:在母串中查找子串,找到返回下表,計(jì)數(shù)從1開(kāi)始。沒(méi)有返回0
SQL>select instr('hello world','llo') from dual
lpad:左填充,參1:待填充的字符串,參2:填充后字符串的總長(zhǎng)度(字節(jié)),參3填充什么
rpad:右填充
SQL>select lpad('abcd',10,'*') 左,rpad('abcd',10,'#') 右 from dual
trim:去掉前后指定的字符
SQL>select trim('H' from 'Hello worldH') from dual;
注意語(yǔ)法,期間含有from關(guān)鍵字
replace:替換
SQL>select replace('hello world','l','*') from dual;
刪除字符串'hello world'中的字符'l'
SQL>select replace('hello world','l','') from dual;
注意:上述的字符函數(shù)都不會(huì)對(duì)數(shù)據(jù)本身作出不可逆轉(zhuǎn)的修改,只是在顯示上做了一些轉(zhuǎn)換。
3.2數(shù)值函數(shù)
ROUND:四舍五入
ROUND (45.926,2) 45.93
round(45.926,2) 2表達(dá)的含義是保留兩位小數(shù),第二個(gè)參數(shù)如果是0可以忽略不寫(xiě)
SQL>select round(45.926,2) 一,round(45.926,1) 二,round(45.926,0) 三,round(45.926,-1) 四,round(45.926,-2) 五 from dual;
一 二 三 四 五
---------- ---------- ---------- ---------- ----------
45.93 45.9 46 50 0
TRUNC:截?cái)?TRUNC(45.926,2) 45.92
MOD:求余
MOD(1600,300) 100
3.3時(shí)間函數(shù)
在Oracle中日期型的數(shù)據(jù),既有日期部分,也有時(shí)間部分。
SQL>select sysdate from dual; (這里沒(méi)有時(shí)間部分,因?yàn)橄到y(tǒng)默認(rèn)的格式中不顯示時(shí)間
SQL>select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
SQL>select to_char(sysdate,'day') from dual 可以顯示當(dāng)前日期星期幾
日期加、減數(shù)字得到的結(jié)果仍為日期。單位:天
顯示:昨天、今天、明天
SQL>select (sysdate-1) 昨天,(sysdate) 今天,(sysdate + 1) 明天 from dual;
SQL>select to_char(sysdate-1,'yyyy-mm-dd') 昨天,to_char(sysdate,'yyyy-mm-dd') 今天,to_char(sysdate+1,'yyyy-mm-dd') 明天 from dual;
既然一個(gè)日期型的數(shù)據(jù)加上或者減上一個(gè)數(shù)字得到的結(jié)果仍為日期,兩個(gè)日期相減,得到的就是相差的天數(shù)。
計(jì)算員工的工齡:
SQL>select ename,hiredate,(sysdate - hiredate) 天,(sysdate - hiredate) / 7 星期,(sysdate - hiredate) / 30 月,(sysdate - hiredate)/365 年 from emp;
!!注意:日期和日期只能相減,不能相加。日期只能和數(shù)字相加
3.4日期函數(shù)
上面求取員工工齡的結(jié)果不精確,如果想將其算精確,可以使用日期函數(shù)來(lái)做
months_between 兩個(gè)日期值相差的月數(shù)(精確值)
SQL>select ename,hiredate,(sysdate-hiredate)/30 一,months_between(sysdate,hiredate) 二 from emp;
add_months:在某個(gè)日期值上,加上多少個(gè)月,正數(shù)向后計(jì)算,負(fù)數(shù)向前計(jì)算。
計(jì)算95個(gè)月以后是哪年、哪月、哪天
SQL>select add_months(sysdate,95) 哪一天 from dual;
last_day:日期所在月的最后一天
SQL>select last_day(sysdate) from dual
next_day:指定日期的下一個(gè)日期
SQL>select next_day(syddate,'星期一') from dual
從當(dāng)前時(shí)間算起,下一個(gè)星期一
round,trunc:對(duì)日期型數(shù)據(jù)進(jìn)行四舍五入和截?cái)?/p>
SQL>select round(sysdate,'month'),round(sysdate,'year') from dual;
SQL>select trunc(sysdate,'month'),round(sysdate,'year') from dual;
3.5轉(zhuǎn)換函數(shù)
在不同的數(shù)據(jù)類型之間完成轉(zhuǎn)換。將“123” 轉(zhuǎn)換為 123 。 有隱式轉(zhuǎn)換和顯示轉(zhuǎn)換之分。
隱式轉(zhuǎn)換:
SQL>select * from emp where hiredate = '17-11月-81' 由Oracle數(shù)據(jù)庫(kù)來(lái)做
顯示轉(zhuǎn)換:
SQL>select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual; 通過(guò)轉(zhuǎn)換函數(shù)來(lái)完成
隱式轉(zhuǎn)換,前提條件是:被轉(zhuǎn)換的對(duì)象是可以轉(zhuǎn)換的。(ABC->625可以嗎?)
Oracle自動(dòng)完成下列轉(zhuǎn)換
源數(shù)據(jù)類型 | 目標(biāo)數(shù)據(jù)類型 |
---|---|
VARCHAR2 or CHAR | NUMBER |
VARCHAR2 or CHAR | DATE |
NUMBER | VARCHAR2 |
DATE | VARCHAR2 |
顯示轉(zhuǎn)換,借助to_char(數(shù)據(jù),格式)、to_number、to_date函數(shù)來(lái)完成轉(zhuǎn)換
如果隱式轉(zhuǎn)換和顯示轉(zhuǎn)換都可以使用,應(yīng)該首選哪個(gè)呢?
- SQL優(yōu)化:如果隱式、顯示都可以使用,應(yīng)該首選顯示,這樣可以省去Oracle的解析過(guò)程
練習(xí):2015-05-11 16:17:06 今天是 星期一輸出
SQL>select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss "今天是" day') from dual)
在固定的格式加入自定義的格式,是可以的,必須要加 “ ”
練習(xí)二:2015-05-11 16:17:06 今天是 星期一 轉(zhuǎn)換為日期
SQL>select to_date('2015-05-11 16:17:06 今天是 星期一','yyyy-mm-dd hh24:mi:ss "今天是" day') from dual;
下面是在TO_CHAR函數(shù)中經(jīng)常使用的幾種格式
查詢員工的薪水,2位小數(shù),本地貨幣代碼,千位符
SQL>select to_char(sal,'L9,999.99') from emp; L9,999.99之間沒(méi)有空格
將¥2,975.00轉(zhuǎn)換成數(shù)字:
SQL>select to_number('¥2,9750.00','L9,999.99') 轉(zhuǎn)換數(shù)字 from dual;
3.6通用函數(shù)
這些函數(shù)適用于任何數(shù)據(jù)類型,同時(shí)也適用于空值
- NVL(expr1,expr2)
- NVL2(expr1,expr2,expr3)
- NULLIF(expr1,expr2)
- COALESCE(expr1,expr2,...,expr n)
nvl2:是nvl函數(shù)的增強(qiáng)版,nvl2(a,b,c) 當(dāng)a = null 返回c,否則返回b
使用nvl2求員工的年收入
SQL>select empno,ename,sal,sal*12,sal*12+nvl2(comm,comm,0) 年薪 from emp
nullif,nullif(a,b) 當(dāng)a=b時(shí)返回null,不相等的時(shí)候返回a值
SQL>select nullif('L9,999.99','L9,999.99') from dual
coalesce:coalesce(a,b,c,...,n)從左向右找參數(shù)中第一個(gè)不為空的值
SQL>select comm,sal,coalesce(comm,sal) 結(jié)果值 from emp;
3.7條件表達(dá)式
例子,老板打算給員工漲工資,要求
總裁(PRESIDENT)漲1000,經(jīng)理(MANAGER)漲800,其他人漲400,請(qǐng)將漲前,漲后的薪水列出
select ename,job sal 漲前薪水,漲后薪水 from emp
思路:
if 是總裁('PRESIDENT') then +1000
else if 是經(jīng)理('MANAGER') then +800
else +400
但是在SQL中無(wú)法實(shí)現(xiàn)if else邏輯,當(dāng)有這種需求的時(shí)候,可以使用case獲得decode
case:是一個(gè)表達(dá)式,其語(yǔ)法為
CASE expr WHEN comparison_expr1 THEN return_expr1
[WHEN comparison_expr2 THEN return_expr2
WHEN comparison_exprn THEN return_exprn
ELSE else_expr]
END
SQL>select ename,job sal 漲前薪水,case job when 'PRESIDENT' then sal+1000
when 'MANAGER' then sal+800
else sal+400
end 漲后薪水
from emp;
注意語(yǔ)法:when then 與下一個(gè)when then 以及end之間沒(méi)有","分隔符
decode:是一個(gè)函數(shù),其語(yǔ)法為:
DECODE(col|expression,search1,result1
[,search2,result2,...,]
[,default])
除第一個(gè)和最后一個(gè)參數(shù)外,中間的參數(shù)都是成對(duì)呈現(xiàn)的(參1,條件,值,條件,值,...,條件,值,尾參)
SQL>select ename,job,sal 漲前薪水,decode(job,'PRESIDENT',sal+1000,
'MANAGER',sal+800,
sal+400) as 漲后薪水
from emp
4.分組函數(shù)
4.1分組函數(shù)
多行函數(shù)也叫組函數(shù)
- 了解組函數(shù)
- 描述組函數(shù)的用途
- 使用GROUP BY 子句數(shù)據(jù)分組
- 使用HAVING 子句過(guò)濾分組結(jié)果集
分組函數(shù)作用域一組數(shù)據(jù),并對(duì)一組數(shù)據(jù)返回一個(gè)值。如:AVG、COUNT、MAX、MIN、SUM操作的是一組數(shù)據(jù),返回一個(gè)結(jié)果
求員工的工資總和
SQL>select sum(sal) from emp; sum()對(duì)指定列的各行求和
員工人數(shù)
SQL>select count(*) from emp ; count()統(tǒng)計(jì)指定列的非空行數(shù)(自動(dòng)慮空)
平均工資
SQL>select sum(sal)/count(*) 方式一,avg(sal) 方式二 from emp
方式一和方式二結(jié)果一樣,當(dāng)有空值的時(shí)候結(jié)果有可能不一樣
※NULL空值:組函數(shù)都有自動(dòng)慮空功能(忽略空值),所以)
SQL>select count(*),count(comm) from emp; 執(zhí)行結(jié)果不相同
如何屏蔽 組函數(shù) 的慮空功能:
SQL>select count(*),count(nvl(comm,0)) from emp;
但是實(shí)際應(yīng)用中,結(jié)果為14和結(jié)果為4都有可能對(duì),看問(wèn)題本身是否要求統(tǒng)計(jì)空值
count函數(shù):求個(gè)數(shù),如果要求不重復(fù)的個(gè)數(shù),要使用distinct
SQL>select count(distinct job) from emp;
4.2分組數(shù)據(jù)
group by
按照group by給定后的表達(dá)式,將from后面的table進(jìn)行分組。針對(duì)每一組,使用組函數(shù)
查詢“部門”的平均工資
分析:結(jié)合select * from emp order by deptno 結(jié)果分析分組
SQL>select deptno,avg(sal)
from emp
group by deptno
order by deptno;
上SQL語(yǔ)句可以抽象成:select a,組函數(shù)(x) from 表 group by a;這樣的格式
如果select a,b ,組函數(shù)(x).......group by 應(yīng)該怎么寫(xiě)
注意:在SELECT 列表中所有沒(méi)有包含在組函數(shù)中的列,都必須在group by 的后面出現(xiàn)。所以上問(wèn)應(yīng)該寫(xiě)成group by a,b;沒(méi)有b語(yǔ)法就會(huì)出錯(cuò),不會(huì)執(zhí)行SQL語(yǔ)句。但,反之可以。Group by a,b,c;c可以不出現(xiàn)在select語(yǔ)句中
group by后面有多列的情況:
SQL>select deptno,job,avg(sal) from emp group by deptno,job order by 1;
分析該SQL的作用:
因?yàn)閐eptno,job兩列沒(méi)有在組函數(shù)里面,所以必須同時(shí)在group by后面。
該SQL的語(yǔ)義:按部門,不同的職位統(tǒng)計(jì)平均工資。先按第一列分組,如果第一列相同,再按第二列分組。
所以查詢結(jié)果中,同一部門中沒(méi)有重復(fù)的職位
常見(jiàn)的非法使用組函數(shù)的情況,主要出現(xiàn)在缺少group by子句。如hr用戶執(zhí)行查詢語(yǔ)句
SELECT department_id,COUNT(last_name)
FROM employees;
會(huì)顯示如下錯(cuò)誤
SELECT department_id,COUNT(last_name)
*
ERROR at line 1:
ORA-00937:not a single-group group function
意為:GROUP BY子句中缺少列
4.3HAVING
使用HAVING過(guò)濾分組
- 行已經(jīng)被分組
- 使用了組函數(shù)
- 滿足HAVING子句中條件的分組江北顯示
其語(yǔ)法:
SELECT column,group_function
FROM table
[WHERE condition]
[GROUP BY group_by_expression]
[HAVING group_condition]
[ORDER BY column]
查詢平均薪水大于2000的部門
分析,該問(wèn)題實(shí)際上是在分組的基礎(chǔ)上過(guò)濾分組
SQL>select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;
- 不能再WHERE子句中使用組函數(shù)(注意)
- 可以在HAVING子句中使用組函數(shù)
從功能上講,where和having都是將滿足條件的結(jié)果進(jìn)行過(guò)濾。但是差別是where子句中不能使用組函數(shù)!
求10號(hào)部門的平均工資
分析:在上一條的基礎(chǔ)上,having deptno=10;此時(shí)where也可以做這件事。
SQL>select deptno,avg(sal) from emp where deptno=10 group by deptno; 因?yàn)闆](méi)有組函數(shù)
在子句中沒(méi)有使用組函數(shù)的情況下,where,having都可以,應(yīng)該怎樣選擇?
※SQL優(yōu)化:盡量采用where
如果有分組的話,where是先過(guò)濾再分組,而having是先分組再過(guò)濾。當(dāng)數(shù)據(jù)量龐大如1億條,where有事明顯。
4.4group by 的增強(qiáng)(擴(kuò)展知識(shí))
問(wèn)題:按照部門統(tǒng)計(jì)各部門不同工種的工資情況,要求按如下格式輸出
分析SQL執(zhí)行結(jié)果。
第一部分?jǐn)?shù)據(jù)是按照deptno和job分組;select查詢deptno,job,sum(sal)
第二部分?jǐn)?shù)據(jù)是直接按照deptno分組即可,與job無(wú)關(guān);select只需要查詢deptno,sum(sal)
第三部分?jǐn)?shù)據(jù)不按照任何條件分組,即group by null;select查詢sum(sal)
所以,整體查詢結(jié)果應(yīng)該=group by deptno, job + group by deptno + group by null
=group by rollup(deptno,job); --group by 語(yǔ)句的增強(qiáng)
抽象成表達(dá)式:
group by rollup(a,b) = group by a,b,group by a + group by null
SQL>select deptno,job,sum(sal) from emp group by rollup(deptno,job);
=========等價(jià)于================
select deptno,job,sum(sal) from emp group by deptno,job;
select deptno,sum(sal) from by deptno
select sum(sal) from emp group by null
5.多表查詢
理論基礎(chǔ)——笛卡爾積
笛卡爾積的行數(shù) = table1的行數(shù) x table2的行數(shù)
笛卡爾積的列數(shù) = table1的列數(shù) + table2 的列數(shù)
多表查詢就是按照給定條件(連接條件),從笛卡爾全集中選出正確的結(jié)果
根據(jù)連接條件的不同可以劃分為:等值鏈接、不等值鏈接、外鏈接、自鏈接
-
Oracle 連接:
- Equijoin:等值鏈接
- Non-equijoin:不等值鏈接
- Outer join:外鏈接
- Self join:自鏈接
-
SQL:1999
- Cross joins
- Natural joins
- Using clause
- Full or two sided outer joins
5.1等值鏈接
從概念上,區(qū)分等值鏈接和不等值鏈接非常簡(jiǎn)單,只需要辨別where子句后面的條件,是“=”為等值連接,不是“=”為不等值鏈接
如果:selecte.empno,e.ename,e.sal,dname from emp e,dept d
直接得到的是笛卡爾全集。其中有錯(cuò)誤結(jié)果。所以應(yīng)該加where條件進(jìn)行過(guò)濾
SQL>SQL>select e.empno,e.ename,e.sal,dname
from emp e,dept d
where e.deptno = d.deptno;
如果有N個(gè)表,where后面的條件至少應(yīng)該有N-1個(gè)
5.2不等值鏈接
將上滿的問(wèn)題稍微調(diào)整下,查詢員工信息:?jiǎn)T工號(hào) 姓名 月薪 和薪水級(jí)別(salgrade表)
分析:SQL>select * from salgrade;
查看員工總的薪水級(jí)別,共有5級(jí),員工的薪水級(jí)別應(yīng)該滿足 >= 當(dāng)前級(jí)別的下線 ,<=該級(jí)別的上限
過(guò)濾子句應(yīng)該: where e.sal >= s.losal and e.sal <= s.hisal
所以:SQL>select e.empno,e.ename,e.sal,s.grade from emp e,salgrade s where e.sal >= s.losal and e.sal <= s.hisal;
更好的寫(xiě)法應(yīng)該是使用between...and
SQL>select s.grade,e.empno,e.ename,e.sal,e.job from emp e,salgrade s
where e.sal between s.losal and s.hisal
order by 1;
5.3外鏈接
按部門統(tǒng)計(jì)員工數(shù),顯示如下信息,部門號(hào) 部門名稱 人數(shù)
分析:
人數(shù):一定是在emp表中,使用count()函數(shù)統(tǒng)計(jì)emp表中任意非空列均可
部門名稱:在dept表dname中,直接讀取即可
部門號(hào):任意兩張表都有
SQL>select e.deptno 部門號(hào),d.dname 部門名稱,count(e.empno) 人數(shù) from emp e,dept d
where e.deptno = d.deptno group by e.deptno,d.dname
注意:由于使用了組函數(shù)count(),所以組函數(shù)外的e.deptno和d.dname必須放到group by 后
得到查詢結(jié)果,但是select * from dept
發(fā)現(xiàn)40號(hào)部門沒(méi)有顯示出來(lái),原因是40號(hào)部門沒(méi)有員工,where沒(méi)有滿足,結(jié)果不對(duì),40號(hào)部門沒(méi)有員工個(gè),應(yīng)該在40號(hào)部門位置顯示0
我們希望,在最后的結(jié)果中,包含某些對(duì)于where條件來(lái)說(shuō)不成立的記錄(外鏈接的作用)
左外連接:當(dāng)where e.deptno = d.deptno 不成立的時(shí)候,=左邊所標(biāo)示的信息,仍然被包含。
寫(xiě)法:與叫法相反: where e.deptno=d.deptno(+)
右外鏈接:當(dāng)where e.deptno=d.deptno不成立的時(shí)候,=右邊所表示的信息,仍然被包含。
寫(xiě)法:依然與叫法相反:where e.deptno(+)=d.deptno
以上我們希望沒(méi)有員工的部門仍然包含到查詢的結(jié)果當(dāng)中。因此應(yīng)該使用外鏈接的語(yǔ)法
SQL>select d.deptno 部門號(hào),d.dname 部門名稱,count(e.empno) 人數(shù) from emp e,dept d
where e.deptno(+)=d.deptno group by d.deptno,d.dname; 右外鏈接的寫(xiě)法
這樣就可以將49號(hào)部門包含到整個(gè)查詢結(jié)果中。人數(shù)是0
注意:不能使用count(e.*)或count(*)
5.4自連接
核心,通過(guò)表的別名,將同一張表視為多張表
查詢員工信息:xxx的老板是yyy
分析:執(zhí)行select * from emp;
發(fā)現(xiàn),員工的老板也在員工表之中,是一張表。要完成多表查詢我們可以假設(shè),有兩張表,一張表e(emp)只存員工,另一張表b(boss)只存員工的老板。——from e,b
老板和員工之間的關(guān)系應(yīng)該是:where e.mgr = b.empno(即員工表的老板 = 老板表的員工)
SQL>select e.ename || ' 的老板是 ' ||b.ename from emp e,emp b where e.mgr = b.empno
執(zhí)行,發(fā)現(xiàn)結(jié)果正確,但是KING沒(méi)有顯示出來(lái)。KING的老板是他自己。應(yīng)該怎么顯示呢?
SQL>select e.ename || ' 的老板是 ' ||b.ename from emp e,emp b where e.mgr = b.empno(+)
完整應(yīng)該是
SQL>select e.ename || ' 的老板是 ' ||nvl(b.ename,'null') relationship from emp e,emp b where e.mgr = b.empno(+)
5.5層次查詢
以上自連接存在一個(gè)問(wèn)題。我們將一張表視為兩張表來(lái)操作。會(huì)產(chǎn)生笛卡爾積問(wèn)題(14 X 14 = 196條記錄),當(dāng)我將該表視為3,4,5或更多張表看待呢?當(dāng)表內(nèi)數(shù)據(jù)有上億條呢?自連接可以滿足需求,但不是最好的。
SQL>select count(*) from emp e,emp b;
可以看出,笛卡爾集是平方的關(guān)系。自連接操作至少是一個(gè)平方的關(guān)系,表越大,笛卡爾集就平方性的在告訴增長(zhǎng)。所以,自連接不適合操作大表。
根據(jù)SQL語(yǔ)句輸出結(jié)果【畫(huà)圖】出員工老板關(guān)系圖。發(fā)現(xiàn)是一個(gè)樹(shù)狀結(jié)構(gòu),共有4層
對(duì)于這種樹(shù)狀結(jié)構(gòu),我們提出層次查詢的概念,用來(lái)取代操作大表時(shí),自連接有可以能帶來(lái)的問(wèn)題。所以,在層次查詢中,只有一張表。否則就會(huì)出現(xiàn)笛卡爾集的問(wèn)題
level偽列是Oracle數(shù)據(jù)庫(kù)幫助我們?cè)诒碇刑砑拥碾[形列,差則有,不查則無(wú)
關(guān)鍵:前一層的員工號(hào)=下一層的老板號(hào)
connect by prior empno=mgr(prior即指定前一層)
遍歷一棵樹(shù):應(yīng)該指定起始點(diǎn)(start with)
起始:start with mgr is null (king之上再?zèng)]有老板了)
SQL>select level,empno,ename,mgr from emp
connect by prior empno=mgr
start with mgr is null
order by 1
總結(jié):層次查詢使用場(chǎng)景,一定只有一張表,同一張表的前后多次操作,進(jìn)行連接,避免笛卡爾集
層次查詢也有缺點(diǎn),沒(méi)有自連接那么直觀
6.子查詢
子查詢語(yǔ)法很簡(jiǎn)單,就是select 語(yǔ)句的嵌套使用
查詢工資比scrott高的員工信息
分析,兩步即可完成
1.查出SCOTT的工資 SQL>select ename,sal from emp where ename='SCOTT'
2.查出比3000高的員工 SQL>select * from emp where sal > 3000
通過(guò)兩部可以將問(wèn)題結(jié)果得到。子查詢,可以將兩步合成一步
——子查詢解決的問(wèn)題:?jiǎn)栴}本身不能一步求解的情況
SQL>select *
from emp
where sal > (select sal
from emp
where ename='SCOTT')
本節(jié)學(xué)習(xí)目標(biāo):
- 描述子查詢可以解決的問(wèn)題
- 定義子查詢(子查詢的語(yǔ)法)
- 列出子查詢的類型
- 書(shū)寫(xiě)單行子查詢和多行子查詢
6.1定義子查詢 需要注意的問(wèn)題
- 合理的書(shū)寫(xiě)風(fēng)格
- 小括號(hào)()
- 主查詢和子查詢可以是不同表,只要子查詢返回的結(jié)果主查詢可以使用即可
- 可以在主查詢的where、select、having、from后都可以放置子查詢
- 不可以在主查詢的group by后面放置子查詢(SQL語(yǔ)句的語(yǔ)法規(guī)范)
- 強(qiáng)調(diào):在from后面放置的子查詢(***) from后面放置是一個(gè)集合(表、查詢結(jié)果)
- 一般先執(zhí)行子查詢(內(nèi)查詢),再執(zhí)行主查詢(外查詢);但是相關(guān)子查詢除外
- 一般不在子查詢中使用order by,但在Top-N分析問(wèn)題中,必須使用order by
- 單行子查詢只能使用單行操作符;多行子查詢只能使用多行操作符
- 子查詢中的null值
6.2主、子查詢?cè)诓煌黹g進(jìn)行
查詢部門名稱是“SALES”的員工信息
主查詢:查詢員工信息。select * from emp;
子查詢:負(fù)責(zé)得到部門名稱(dept表中)、部門號(hào)對(duì)應(yīng)關(guān)系。select deptno from dept where dname='SALES'
SQL>select *
from emp
where deptno=(select deptno
from dept
where dname='SALES')
主查詢,查詢的是員工表emp,子查詢,查詢的是部門表dept.是兩張不同的表
將該問(wèn)題使用“多表查詢”解決
SQL>select e.* from emp e,dept d where e.deptno=d.deptno and d.dname='SALES'
兩種方式哪種好呢?
※SQL優(yōu)化:理論上,既可以使用子查詢,也可以使用多表查詢,盡量使用“多表查詢”。子查詢有2次from
不同數(shù)據(jù)庫(kù)處理數(shù)據(jù)的方式不盡相同,如Oracle數(shù)據(jù)庫(kù)中,子查詢地位比較重要,做了深入的優(yōu)化,有可能實(shí)際看到結(jié)果是子查詢快于多表查詢
6.3在主查詢的where、select、having、from 放置子查詢
子查詢可以放在select后,但,要求該子查詢必須是單行子查詢;(該子查詢本身只返回一條記錄,2+叫多行子查詢)
SQL>select empno,ename,(select dname from dept where deptno=10) 部門 from emp
注意:SQL中沒(méi)有where是不可以的,那樣是多行子查詢
進(jìn)一步理解查詢語(yǔ)句,實(shí)際上是在表或集中通過(guò)列名來(lái)得到行數(shù)據(jù),子查詢?nèi)绻嵌嘈校瑂elect無(wú)法做到這一點(diǎn)
在having后和where類似。但需注意在where后面不能使用組函數(shù)
6.4在from后面放置子查詢
表,代表一個(gè)數(shù)據(jù)集合、查詢結(jié)果(SQL)語(yǔ)句本身也代表一個(gè)集合。
查詢員工的姓名、薪水和年薪
SQL>select * from (select ename,sal,sal*12 年薪 from emp);
將select語(yǔ)句放置在from后面,表示將select語(yǔ)句的結(jié)果,當(dāng)成表來(lái)看待。這種查詢方式在Oracle語(yǔ)句中使用比較頻繁
6.5一般先執(zhí)行子查詢,再執(zhí)行主查詢
含有子查詢的SQL語(yǔ)句執(zhí)行的順序是,先子后主。但,相關(guān)子查詢例外
6.6一般不在子查詢中使用Order by
一般情況下,子查詢使用order by或者不適用order by 對(duì)主查詢來(lái)說(shuō)沒(méi)有什么意義。子查詢的結(jié)果給子查詢當(dāng)成集合來(lái)使用,所以沒(méi)有必要將子查詢order by
但,在Top-N分析問(wèn)題中,必須使用order by
6.6.1找到員工表中工資最高的前三名, 要求按如下格式輸出
——涉及Top-N分析問(wèn)題。
一般不在子查詢中使用order by, 但在Top-N分析問(wèn)題中,必須使用order by
SQL>select rownum,empno,ename,sal
from emp
where rownum<=3
order by sal desc
結(jié)果并不正確
補(bǔ)充知識(shí):rownum 行號(hào)(偽列)
SQL> select rownum, empno, ename, sal from emp
借助行號(hào)將薪水降序排列。前三條即是我們想要的內(nèi)容。
SQL> select * from emp order by sal desc 但問(wèn)題是如何取出前三行。
SQL> select * from emp where rownum <= 3 order by sal 發(fā)現(xiàn)取出的結(jié)果不正確。
--------釜底抽薪,正確的做法--------------
SQL>select rownum,empno,ename,sal
from (select empno,ename,sal
from emp
order by sal desc)
where rownum<=3
order by sal desc
因?yàn)閞ownum是對(duì)from中源進(jìn)行自動(dòng)編號(hào)的,所以可以先對(duì)from中的源進(jìn)行排序!
行號(hào)rownum需要注意的問(wèn)題:
1. rownum永遠(yuǎn)按照默認(rèn)的順序生成。
SQL> select rownum, empno, ename, sal from emp order by sal desc
——發(fā)現(xiàn)行號(hào)是跟著行走的。查詢結(jié)果順序變了,行號(hào)依然固定在原來(lái)的行上。
行號(hào)始終使用默認(rèn)順序:select * from emp所得到的順序,沒(méi)有排序,沒(méi)有分組等。
只要能使行號(hào)隨著重新排序,發(fā)生改變,那么取前三條記錄,就是我們想要的結(jié)果。
2.rownum只能使用<, <=符號(hào),不能使用>,>=符號(hào)。
想將現(xiàn)有的表進(jìn)行分頁(yè)。1-4第一頁(yè),5-8第二頁(yè)……
SQL> select rownum, empno, ename, sal from emp where rownum >=1 and rownum<=4
SQL> select rownum, empno, ename, sal from emp where rownum >=5 and rownum<=8
執(zhí)行,發(fā)現(xiàn)結(jié)果:未選定行。原因是rownum不能使用>=符號(hào)。Where永遠(yuǎn)為假。
與行號(hào)生成的機(jī)制有關(guān):Oracle中的行號(hào)永遠(yuǎn)從1開(kāi)始——取了1才能取2,取了2才能取3,…… <=8可以是因?yàn)?234567挨著取到,而>=5不行,因?yàn)闆](méi)有1234,不能直接取5。
---------------分頁(yè)唯一辦法---------------------
分析:我只能1-4,不能5-8,所以看下面的select語(yǔ)句
我可以取到1-8的數(shù)據(jù)集合,我剔除1-4,剩下的,就是5-8了。就可以避開(kāi)rownum的限制了,讓rownum不再是偽列
select rownum,empno,ename,sal
from (select empno,ename,sal
from emp
order by sal desc)
where rownum<=8
--------------------------
select *
from (select rownum r,empno,ename,sal
from (select empno,ename,sal
from emp
order by sal desc)
where rownum<=8)
where r >= 5
#不能使用rownum>=5,因?yàn)榻馕銎鲿?huì)解析成偽列
#所以要利用別名機(jī)制!
6.6.2找到emp表中薪水大于本部門平均薪水的員工
select e.empno,e.ename,e.sal,d.avgsal
from emp e,(select deptno,avg(sal) avgsal
from emp
group by deptno ) d
where e.deptno = d.deptno and e.sal > d.avgsal
#組函數(shù)avg()不能再where句中使用
#利用別名機(jī)制
6.6.3統(tǒng)計(jì)每年入職的員工個(gè)數(shù)
——員工的入職年份是已知條件——1980、1981、1982、1987這4個(gè)。
要統(tǒng)計(jì)每年入職的人數(shù),一定要知道每個(gè)員工的入職日期,可以通過(guò)查詢hiredate列來(lái)得到。
SQL> select hiredate from emp;
結(jié)合查詢結(jié)果,以1981年為例,如何統(tǒng)計(jì)出81年入職的有多少個(gè)人呢?可以從寫(xiě)C程序的角度入手。
思路:定義一個(gè)計(jì)數(shù)器count=0; 有一個(gè)81年的員工,就+1,不是81的就+0;最后查看count的值就可以了。
求和,使用sum函數(shù),內(nèi)部邏輯:sum(if 是81年 then +1 else +0)
也就是取員工的hiredate列的“年”那一部分,與81比較,進(jìn)行判斷。
to_char(hiredate, ‘yyyy’) 得到年,與‘1981’進(jìn)行比較。
select count(*) Total,
sum(decode(to_char(hiredate,'yyyy'),'1980',1,0)) "1980",
sum(decode(to_char(hiredate,'yyyy'),'1981',1,0)) "1981",
sum(decode(to_char(hiredate,'yyyy'),'1982',1,0)) "1982",
sum(decode(to_char(hiredate,'yyyy'),'1987',1,0)) "1987"
from emp
6.7 單行子查詢只能使用單行操作符;多行子查詢只能使用多行操作符
6.7.1單行子查詢
單行子查詢就是該條子查詢執(zhí)行結(jié)束時(shí),只返回一條記錄(一行數(shù)據(jù))。
使用單行操作符:
= 、>、 >=、< 、<=、 <>
- 單行子查詢,只能使用單行操作符(=號(hào)、>號(hào))
- 在一個(gè)主查詢總可以有多個(gè)子查詢
- 子查詢里面可以嵌套多層子查詢
- 子查詢也可以使用組函數(shù)。子查詢也是查詢語(yǔ)句,適用于前面所有知識(shí)
非法使用子查詢的例子
select employee_id,last_name
from employees
where salary =
(select MIN(salary)
from employees
group by department_id);
#group by 可以在子查詢中使用
#但是返回的是多條數(shù)據(jù)
#單行操作符“=”連接了返回多條記錄的子查詢,查詢語(yǔ)句執(zhí)行會(huì)報(bào)錯(cuò)
6.7.2多行子查詢
子查詢返回2條記錄以上就叫多行
多行操作符有:
IN 等于列表中的任意一個(gè)
ANY 和子查詢返回的任意一個(gè)值比較
ALL 和子查詢返回的所有值比較
IN(表示集合中):
查詢部門名稱為SALES和ACCOUNTING的員工信息
分析:
部門名稱在dept表中,員工信息在emp表中
子查詢應(yīng)先去dept表中將SALES和ACCOUNTING的部門號(hào)得好,交給主查詢員工信息
SQL>select *
from emp
where deptno in (select deptno
from dept
where dname='SALES' or dname='ACCOUNTING');
使用多表查詢 來(lái)解決問(wèn)題
SQL>select e.*
from emp e,dept d
where e.deptno=d.deptno and (d.dname='SALES' or d.dname='ACCOUNTING');
ANY(表示和集合中的任意一個(gè)值比較,這里理解為比最小的大)
查詢薪水比30號(hào)部門任意一個(gè)員工高的員工信息
分析:首先查出30號(hào)部門的員工薪水的集合,然后 > 它就得到該員工信息
SQL>select *
from emp
where sal > ANY(select sal
from emp
where deptno = 30);
ALL(表示和集合中的所有制比較):
查詢薪水比30號(hào)部門所有員工高的員工信息
SQL>select *
from emp
where sal > all(select sal from emp where deptno=30);
同樣,將該題改成單行子句查詢
SQL>select *
from emp
where sal >(select max(sal)
from emp
where deptno=30);
對(duì)于any和all來(lái)說(shuō),究竟取最大值還是取最小值,不一定。將上面的兩個(gè)例子中的“高”換成“低”,any和all就各取相反的值了
6.8子查詢中Null
判斷一個(gè)值等于、不等于空,不能使用=和!=號(hào),而應(yīng)該使用is和not
如果集合中有NULL值,不能使用not in 如:not in(10,20,NULL),但是可以使用in。為什么呢?
先看一個(gè)例子:
查詢不是老板的員工信息:
分析:不是老板就是樹(shù)上的葉子節(jié)點(diǎn)。在emp表中有列mgr,該列表示該員工的老板的員工號(hào)是多少。那么,如果一個(gè)員工的員工號(hào)在這列中,那么說(shuō)明這員工是老板,如果不在,說(shuō)明他不是老板
SQL>select * from emp where empno not in (select mgr from emp); 但是運(yùn)行沒(méi)有結(jié)果,因?yàn)橛蠳ULL
查詢是老板的員工的員工信息:
SQL>select * from emp where empno in (select mgr from emp);
還是我們之前Null的結(jié)論:in(10,20,null)可以,not in(10,20,null)不可以
例如:a not in(10,20,null)等價(jià)于(a != 10) and (a != 20) and (a != NULL)
因?yàn)椋琻ot in 操作符等價(jià)于 !=ALL ,最后一個(gè)表達(dá)式為假,整體假。如
select emp.last_name
from employees emp
where emp.employee_id NOT IN
(select mgr.manager_id
from employees mgr);
a in(10,20,null) 等價(jià)于 (a = 10) or (a=20) or (a = null)只要有一個(gè)為真即為真
in 操作符等價(jià)于 = Any
所以在子查詢中,如果有Null值,主查詢使用where xxx=子查詢結(jié)果集。永遠(yuǎn)為假
繼續(xù),查詢不是老板的員工信息。只要將空值去掉即可
SQL>select *
from emp
where empno not in
(select mgr
from emp
where mgr is not null)
7.集合運(yùn)算
查詢部門號(hào)是10和20的員工信息:
1. SQL>select * from emp where deptno in(10,20);
2. SQL>select * from emp where deptno=10 or deptno=20;
3. 集合運(yùn)算
select * from emp where deptno = 10 加上
select * from emp where deptno = 20
集合運(yùn)算所操作的對(duì)象是兩個(gè)或者多個(gè)集合,而不再是表中的列(select 一直在操作表中列)
7.1集合運(yùn)算符
集合運(yùn)算的操作符。A∪B、A∩B、A-B
select * from emp where deptno=20
union
select * from emp where deptno=10
這是一條SQL語(yǔ)句
7.2集合運(yùn)算需要注意的問(wèn)題
- 參與運(yùn)算的各個(gè)集合必須列數(shù)相同,且類型一致
- 采用第一個(gè)集合的表頭作為最終使用的表頭
- 如果要order by,必須在每個(gè)集合后使用相同的order by,最后結(jié)果會(huì)按要求排序
- 可以使用括號(hào)()先執(zhí)行后面的語(yǔ)句
select deptno,job,sum(sal) from emp group by deptno,job
union
select deptno,to_char(null),sum(sal) from emp group by deptno,job
union
select to_number(null),to_char(null),sum(sal) from emp;
#這個(gè)是4.4group by增強(qiáng)例子的另一種解法,代替了rollup
#因?yàn)閐eptno是數(shù)字類型,所以是to_number(null)