柚子快報(bào)激活碼778899分享:數(shù)據(jù)庫(kù)基礎(chǔ)教程(Oracle)
柚子快報(bào)激活碼778899分享:數(shù)據(jù)庫(kù)基礎(chǔ)教程(Oracle)
1 數(shù)據(jù)庫(kù)
1.1 什么是數(shù)據(jù)庫(kù)?
車(chē)庫(kù):放汽車(chē)的倉(cāng)庫(kù),實(shí)體化米庫(kù):放大米的倉(cāng)庫(kù),實(shí)體化數(shù)據(jù)庫(kù):放數(shù)據(jù)的倉(cāng)庫(kù),數(shù)據(jù)化
我們口中的數(shù)據(jù)庫(kù):
是數(shù)據(jù)庫(kù)管理系統(tǒng)和數(shù)據(jù)庫(kù)組成倉(cāng)庫(kù)管理系統(tǒng)和倉(cāng)庫(kù)
1. 1.1 數(shù)據(jù)的發(fā)展歷史
生活中的存放數(shù)據(jù)的方式
筆記本、手機(jī)、竹筒、計(jì)算機(jī)文檔、表格、數(shù)據(jù)庫(kù)
手工管理:容易丟、修改困難、數(shù)據(jù)量多不好處理、不方便查找文檔文件:使用方便、什么都要面面俱到、電腦不能壞、查找不方便數(shù)據(jù)庫(kù):彌補(bǔ)了大部分缺點(diǎn),對(duì)使用人群有限制
優(yōu)勢(shì):持久化,數(shù)據(jù)共享,數(shù)據(jù)一致性,數(shù)據(jù)安全性,高效性(SQL)
1.2 數(shù)據(jù)庫(kù)的特性
原子性:原子性確保一個(gè)事務(wù)被視為一個(gè)不可分割的工作單元。這意味著要么事務(wù)中的所有更改都提交到數(shù)據(jù)庫(kù),要么都不提交。如果事務(wù)的任何部分失敗,整個(gè)事務(wù)都將回滾,數(shù)據(jù)庫(kù)恢復(fù)到之前的狀態(tài)。一致性:一致性確保事務(wù)將數(shù)據(jù)庫(kù)從一個(gè)有效狀態(tài)轉(zhuǎn)換為另一個(gè)有效狀態(tài)。它強(qiáng)制執(zhí)行對(duì)數(shù)據(jù)庫(kù)定義的完整性約束和規(guī)則,以使數(shù)據(jù)庫(kù)在事務(wù)之前和之后保持一致的狀態(tài)。隔離性:隔離性確保并發(fā)事務(wù)不會(huì)相互干擾。每個(gè)事務(wù)都像在隔離環(huán)境中執(zhí)行一樣,即使可能有多個(gè)事務(wù)同時(shí)執(zhí)行。隔離性防止出現(xiàn)臟讀、不可重復(fù)讀和幻讀等問(wèn)題。持久性:持久性保證一旦事務(wù)提交并將更改保存到數(shù)據(jù)庫(kù)中,即使系統(tǒng)發(fā)生故障(如斷電或崩潰),更改也會(huì)持久存在。更改變得永久且無(wú)法撤銷(xiāo)。
1.2.1 數(shù)據(jù)庫(kù)表之間的關(guān)系
一對(duì)一:每個(gè)員工只有一個(gè)工作時(shí)間一對(duì)多:一個(gè)顧客ID可以對(duì)應(yīng)很多個(gè)訂單ID,但是一個(gè)訂單只能有一個(gè)顧客多對(duì)多:很多菜可以對(duì)應(yīng)一個(gè)顧客,很多顧客可以對(duì)應(yīng)很多菜
1.2.2 數(shù)據(jù)庫(kù)的分類(lèi)
關(guān)系型數(shù)據(jù)庫(kù):采用關(guān)系模型來(lái)組織數(shù)據(jù)的,處理簡(jiǎn)單的文字?jǐn)?shù)據(jù),可以用表來(lái)存儲(chǔ)并且可以直觀表達(dá)的
常見(jiàn)的:Oracle、MySQL、SQL serve...
非關(guān)系型數(shù)據(jù)庫(kù):主要針對(duì)的是高可用、高擴(kuò)展、性能,處理這種高并發(fā)的數(shù)據(jù)、表內(nèi)存儲(chǔ)不了的,視頻、音頻、圖片...
常見(jiàn)的:Mong DB、DB2、Redius...
關(guān)系型數(shù)據(jù)庫(kù)相當(dāng)于非關(guān)系型數(shù)據(jù)庫(kù)的優(yōu)勢(shì):
數(shù)據(jù)一致性:使用ACID來(lái)管理數(shù)據(jù),保證了數(shù)據(jù)的完整性結(jié)構(gòu)化:采用的是表格化的方式來(lái)管理數(shù)據(jù),結(jié)構(gòu)清晰可靠性:有更成熟的查詢語(yǔ)句(SQL)
1.2.3 什么是SQL?
是一個(gè)編程語(yǔ)言,可以用來(lái)增刪改查數(shù)據(jù)庫(kù),是一種標(biāo)準(zhǔn)化語(yǔ)言
分類(lèi):
DQL:數(shù)據(jù)查詢語(yǔ)句,查詢數(shù)據(jù),關(guān)鍵詞:selectDML:數(shù)據(jù)操作語(yǔ)句,增刪改數(shù)據(jù),關(guān)鍵詞:insert、update、deleteDDL:數(shù)據(jù)定義語(yǔ)句,創(chuàng)建數(shù)據(jù)庫(kù)的表、索引、視圖、游標(biāo)、序列,關(guān)鍵詞:create、define、alter、dropDCL:數(shù)據(jù)控制語(yǔ)句,用于對(duì)用戶的授權(quán),關(guān)鍵詞:grant、alter、revokeTCL:事務(wù)控制語(yǔ)句,用于控制事務(wù)的提交、回滾等等,關(guān)鍵詞:commit、rollback
1.2.4 Oracle
1.2.4.1 什么是Oracle
甲骨文,是一個(gè)數(shù)據(jù)庫(kù)
版本:“”
Oracle 7:支持分布式數(shù)據(jù)庫(kù)和存儲(chǔ)過(guò)程O(píng)racle 8:支持Java、物理化視圖、分區(qū)表Oracle 9i(Internet):支持XML、RACOracle 10g(grocery):新增手動(dòng)調(diào)優(yōu)Oracle 11g:新增自動(dòng)調(diào)優(yōu)Oracle 12c(cloud):新增存儲(chǔ)序列,并且支持云端
1.3 數(shù)據(jù)庫(kù)安裝
1.3.1 上傳解壓工具7z
上傳完安裝
1.3.2 上傳Oracle10ge安裝文件
上傳完成利用7z解壓
?1.3.3 找到安裝文件開(kāi)始安裝
1.3. 4 開(kāi)始安裝
?
?不用管這個(gè)頁(yè)面
?
1.3.5? 在2003里cmd測(cè)試連接
sqlplus / as sysdba
1.3.6?查看數(shù)據(jù)庫(kù)服務(wù)名
?select instance_name from v$instance
?解壓遠(yuǎn)程連接工具,路徑不能有中文和特殊符號(hào)
在instantclient的路徑輸入cmd打開(kāi)cmd窗口輸入下方命令測(cè)試連接
sqlplus sys/密碼@//數(shù)據(jù)庫(kù)IP:1521/服務(wù)名 as sysdba
數(shù)據(jù)庫(kù)IP就是你安裝數(shù)據(jù)庫(kù)的虛擬機(jī)的IP
?查詢用戶
?連接成功
配置環(huán)境變量,兩個(gè)地方,一個(gè)外部一個(gè)path內(nèi)部
路徑選擇你自己存放的路徑,不能有中文和特殊符號(hào)
?配置TNS協(xié)議
使用別名測(cè)試登錄
sqlplus sys/密碼@別名 as sysdba
中文配置的環(huán)境變量
NLS_LANG
AMERICAN_AMERICA.ZHS16GBK
SIMPLIFIED CHINESE_CHINA.ZHS16GBK
解壓PLSQL
?打開(kāi)登錄軟件
查詢?nèi)坑脩?/p>
select * from all_users;
?
修改密碼并解鎖scott用戶
alter user scott identified by "123456";
alter user scott account unlock;
使用scott用戶登錄
?永久注冊(cè)
?
?
測(cè)試
-- 查詢emp表的內(nèi)容
select * from emp;
-- 查詢scott用戶擁有的表
select * from user_tables;
?
什么是單表查詢?
在一張表內(nèi)的查詢操作,就叫單表查詢
PLSQL軟件
?默認(rèn)表EMP表介紹
2 查詢(select)
要求:
必須是英文符號(hào)養(yǎng)成習(xí)慣分號(hào)結(jié)尾表名,字段名不區(qū)分大小寫(xiě),內(nèi)容區(qū)分大小寫(xiě)
2.1 基本查詢
select * from 表名;
select * from emp;
select * from salgrade;
2.1.1?指定字段查詢
字段:每個(gè)表內(nèi)容的標(biāo)題
*代表全部字段,多個(gè)字段查詢是,字段之間使用逗號(hào)隔開(kāi)
select 字段 from 表名;
select ename,job,sal from emp;
2.1.2 條件查詢(where)
select 字段 from 表名 where 條件;
-- 條件:字符用單引號(hào)包裹,數(shù)字不需要
select ename,job from emp where job = 'SALESMAN';
select ename,sal from emp where sal > 2000;
-- 工作是CLERK的人的工資
select sal,ename from emp where job = 'CLERK';
2.1.3 多個(gè)條件查詢(and)
select 字段 from 表名 where 條件1 and 條件2;
-- 工作是 CLERK 并且工資大于 1000 的人
select ename,sal,job from emp where job = 'CLERK' and sal > 1000;
-- 有工資大于2000并且是部門(mén)10的人
-- 有工資大于2000并且是部門(mén)10的人
2.1.4 Null值的判斷
is null : 值是空值
is not null : 不是空值,0不是空值
select 字段 from 表名 where 字段 判斷空值;
-- 查詢有獎(jiǎng)金的人
select comm,ename from emp where comm is not null;
-- 查詢沒(méi)有上級(jí)編號(hào)的人
select ename,mgr from emp where mgr is null;
2.1.5 別名(as)
給表或者字段取一個(gè)別名,方便我們記憶,as可以省略
select 字段 as 別名 from 表名 別名 ...;
注意事項(xiàng)
給表取了別名,使用字段時(shí)要用別名來(lái)聲明字段
select e.ename from emp e;
2.1.6 去重(distinct)
作用:去除重復(fù)值
select distinct(字段) from emp ...; -- 查詢有哪些部門(mén)
2.1.7 排序(order by)
作用:對(duì)查詢出來(lái)的數(shù)據(jù)進(jìn)行排序
asc:升序,一般不加,默認(rèn)升序
desc:降序
select 字段 from 表名 order by 字段 asc/desc ...;
-- 排序工資
select sal,ename from emp order by sal asc;
2.1.8 面對(duì)空值
默認(rèn)是最大值,可以使用 nulls first 和 nulls last 調(diào)整空值的順序
select 字段 from 表名 order by 字段 asc/desc nulls first/last ...;
-- 排序獎(jiǎng)金
select comm,ename from emp order by comm asc nulls first;
2.1.9 模糊查詢(like)
作用:部分匹配
_:一個(gè)下劃線代表一個(gè)字符
%:代表全部字符
select 字段 from 表名 where 字段 like '值' ...;
-- 查詢名字是S開(kāi)頭的
select ename from emp where ename like 'S____';
select ename from emp where ename like 'S%';
2.1.10 算數(shù)運(yùn)算符 (+-*/)
通常使用在字段中
select 字段+-*/ from 表名 ...;
-- 給每個(gè)員工漲 500 塊錢(qián)工資 select 500 + sal 新工資,sal 舊工資 from emp;
2.1.11 比較運(yùn)算符 (> < >= <= !=)
通常使用在條件里
!=:不等于
-- 查詢不是部門(mén) 10 的人
select ename,deptno from emp where deptno != 10;
2.1.12 邏輯運(yùn)算符 (and,or,not)
and:與的關(guān)系,表并列,連接兩個(gè)表達(dá)式,只有二者都成立菜返回結(jié)果
or:或的關(guān)系,連接兩個(gè)表達(dá)式,只有一個(gè)成立就可以返回結(jié)果
not:非的關(guān)系,用在表達(dá)式之前,表示取反
-- 查詢來(lái)自部門(mén) 10 或者部門(mén) 20 的人的姓名
select ename,deptno from emp where deptno = 10 or deptno = 20;
-- 查詢不是來(lái)自部門(mén) 10 或者部門(mén) 20 的人的姓名
select ename,deptno from emp where not(deptno = 10 or deptno = 20);
select ename,deptno from emp where not deptno in (10,20); -- 使用 in + or
2.1.13 區(qū)域條件(between and)
select 字段 from 表名 where 字段 between 條件1 and 條件2 ...;
-- 查詢工資在1000~2000之間的員工
select ename,sal from emp where sal between 1000 and 2000;
2.2 函數(shù)
通過(guò)函數(shù)名來(lái)使用一些特定的功能 sum:求和函數(shù),函數(shù)是可以套用的,函數(shù)的變量位置不是單純的只能放字段、字符串,函數(shù)之間是可以套用的
2.2.1 字符串函數(shù)
2.2.1.1大小寫(xiě)控制(upper、lower)
upper:轉(zhuǎn)大寫(xiě)
lower:轉(zhuǎn)小寫(xiě)
select lower(ename) 小寫(xiě)名字 from emp;
select upper('aaaa') 大寫(xiě)字母 from dual;
2.2.1.2首字母大寫(xiě)(initcap)
select initcap(lower(ename)) 首字母大寫(xiě) from emp;
2.2.1.3 字符串拼接(concat,||)
select concat('Dear',ename) DearName from emp;
select 'Dear' || lower(ename) from emp;
2.2.1.4 字符串提?。╯unstr)
select ename,substr(ename,3,2) from emp;
2.2.1.5 字符串查找(instr)
select ename,instr(ename,'I',2) from emp;
-- 截取字符串 Hello world!當(dāng)中的 wo
select instr('Hello world!','wo') from dual;
如果不加最后一個(gè)截取個(gè)數(shù),返回的值是截取的是第幾位
2.2.1.6 返回字符的長(zhǎng)度(length、lengthb)
英文的字符等于字節(jié)數(shù),中文的1:2
select length(sname) 字符數(shù),lengthb(sname) 字節(jié)數(shù) from student;
小練習(xí)
-- 查找員工姓名是五個(gè)字母的員工 select length(ename) 長(zhǎng)度,ename from emp where length(ename) = 5;
2.2.1.7 左右填充函數(shù)(ipad,rpad)
ipad:左填充
rpad:右填充
select lpad(ename,10,'*') from emp; -- 給 SMITH 右邊填充 3 個(gè)星號(hào) select rpad(ename,8,'*') from emp;
2.2.1.8去除字符串前后的字符(trim)
使用from連接
select trim('*' from rpad(ename,8,'*')) 去除星號(hào) from emp;
2.2.1.9 字符串替換(replace)
select replace(concat('Dear',ename),'Dear','-') from emp;
2.2.2 數(shù)學(xué)函數(shù)
2.2.2.1 四舍五入(round)
select round(123.456) from dual;
截?cái)啵╰runc)
select trunc(123.456) from dual; -- 123
求余(mod)
mod(除數(shù),被除數(shù))
select mod(100,3) from dual; -- 3
取整(ceil、floor)
ceil:向上取整,去除小數(shù)位整數(shù)位+1
floor:向下取整,去除小數(shù)位
select ceil(123.123),floor(456.789) from dual; -- 124 456
2.2.2.2 日期函數(shù)
當(dāng)前所用時(shí)間是 2023-07-25-13:50~
顯示當(dāng)前日期和時(shí)間(sysdate、systimestamp)
select sysdate,systimestamp from dual;
2.2.2.3 返回當(dāng)前時(shí)間和日期
current_date、current_timestamp、localtimestamp
select current_date,current_timestamp,localtimestamp from dual;
2.2.2.4 給指定的日期添加月份(add_months)
select hiredate,add_months(hiredate,2) from emp;
2.2.2.5 當(dāng)前月的最后一天(last_day)
select hiredate,last_day(hiredate) from emp;
2.2.2.6 抽取日期的單位(extract)
select extract(year from hiredate) year from emp;
select extract(month from hiredate) month from emp;
select extract(day from hiredate) day from emp;
select extract(hour from systimestamp) hour from dual;
select extract(minute from systimestamp) minute from dual;
select extract(second from systimestamp) second from dual;
2.2.2.7返回兩個(gè)日期之間的月份(months_between)
select ceil(months_between(sysdate,hiredate)) months from emp;
2.2.2.8 返回下一個(gè)周幾(next_day)
不是下一周是下一個(gè)
select next_day(sysdate,'星期五') from dual;
2.2.3 轉(zhuǎn)換函數(shù)
2.2.3.1 字符串轉(zhuǎn)日期(to_date)
select to_date('2023-07-25','yyyy-mm-dd') from dual;
2.2.3.2. 日期轉(zhuǎn)字符串(to_char)
select to_char(sysdate,'yyyy') year from dual; -- 23
select to_char(sysdate,'mm') months from dual; -- 07
select to_char(sysdate,'dd') day from dual; -- 25
select to_char(sysdate,'day') week from dual; -- 返回當(dāng)前星期幾 星期二
2.2.3.3 字符串轉(zhuǎn)數(shù)字(to_numbner)
select to_number('20230725') from dual;
-- 轉(zhuǎn)有效數(shù)字
select to_number('$123.456','$999.9999') from dual;
-- 16進(jìn)制轉(zhuǎn)10進(jìn)制
select to_number('19f','xxx') from dual;
2.2.3.4 通用函數(shù)
nvl
nvl(值1,值2) 如果值1為空返回值2
-- 如果獎(jiǎng)金為空,給他500獎(jiǎng)金
select nvl(comm,500) from emp;
nvl2
nvl2(值1,值2,值3) 如果值1為空返回值3,否則返回值2
select nvl2(comm,comm+500,1500) 漲獎(jiǎng)金,comm from emp;
nullif
nullif(值1,值2),如果值1等于值2,返回null,反之返回值1
select nullif(500,null) from dual;
coalesce
coalesce(值1,值2,值3,....)返回第一個(gè)不為空的值
select coalesce(comm,deptno) from emp;
2.2.4 條件函數(shù)
case when
case when 值1 then 返回值1
when 值2 then 返回值2
...
else 其他值
end
-- 判斷員工的部門(mén)名稱(chēng)。如果是 10 我們叫 財(cái)務(wù)部
-- 如果是 20 我們叫 研發(fā)部
-- 如果是 30 我們叫 銷(xiāo)售部
select emp.*,
case when deptno = 10 then '財(cái)務(wù)部'
????????when deptno = 20 then '研發(fā)部'
????????when deptno = 30 then '銷(xiāo)售部'
else '其他部門(mén)'
end 部門(mén)名稱(chēng)
from emp;
decode
decode (條件,值1,返回值1,
????????????????????????值2,返回值2
???????????????????????? ...,
????????????????????????值n,返回值n,
????????????????????????其他值)
如果 條件 = 值1,輸出返回值1
如果 條件 = 值2,輸出返回值2
都不滿足 返回其他值
-- 判斷員工的部門(mén)名稱(chēng)。如果是 10 我們叫 財(cái)務(wù)部
-- 如果是 20 我們叫 研發(fā)部
-- 如果是 30 我們叫 銷(xiāo)售部
select emp.*,
???????????????? decode(deptno,10,'財(cái)務(wù)部',
????????????????????????????????????????????????20,'研發(fā)部',
????????????????????????????????????????????????30,'銷(xiāo)售部',
????????????????????????????????????????????????'其他部門(mén)') 部門(mén)名稱(chēng)
from emp;
2.2.5 聚合函數(shù)(分組函數(shù))
括號(hào)里面放字段
max() -- 最大值
min() -- 最小值
avg() -- 平均值
count() -- 數(shù)量
sum() -- 求和
select max(sal),min(sal),avg(sal),count(sal),sum(sal) from emp;
count(*),count(1) 都代表總內(nèi)容數(shù),多少行數(shù)據(jù)
select count(*) from emp;
2.2.5.1 分組語(yǔ)句 (group by)
對(duì)指定的字段分組,比如部門(mén)有10,20,30,如果是 group by deptno,就是對(duì)部門(mén)分組,分成10一組,20一組,30一組
select 字段 from 表名 where 條件 group by 字段 ...;
-- 求每個(gè)部門(mén)的平均工資
select deptno,trunc(avg(sal)) 平均工資 from emp group by deptno;
注意事項(xiàng)
1. 出現(xiàn)在 select 后面的字段,如果不是在分組函數(shù)中,那么他必須同時(shí)出現(xiàn)在 group by 語(yǔ)句當(dāng)中
2. 出現(xiàn)在 group by 后面的字段不一定出現(xiàn)在 select 后面
3. where 語(yǔ)句中不允許出現(xiàn) group by
分組語(yǔ)句的條件(having)
用法與 where 一樣,having 條件
區(qū)別:
1. having 服務(wù)對(duì)象是 group by,where 服務(wù)對(duì)象是字段
2. where 不能用分組函數(shù),having 通過(guò)條件過(guò)濾分組函數(shù)
3. having 是在分組完成后執(zhí)行,where 是在分組前執(zhí)行,這也是為什么 where 不能服務(wù) group by 的原因
-- 分部門(mén)和職業(yè)統(tǒng)計(jì)員工的工資和,并且工資和 > 3000
1.group by deptno,job
2.having sum(sal) > 3000
3.deptno,job,sum(sal)
4.select deptno,job,sum(sal) from emp group by deptno,job having sum(sal) > 3000;
2.2.6 查詢順序
1. from table
2. where example
3. group by title
4. having
5. select
6. order by answer
3 連續(xù)查詢
3.1 笛卡爾積
兩個(gè)表的一種關(guān)聯(lián)方式,將第一張表中的每一行都與第二張表中的每一行組合,生成一個(gè)新的表
舉例:兩個(gè)表A和表B
表A
?表B
?笛卡爾積后---> 表C
3.2 等值連接查詢
我們從多張表中查詢數(shù)據(jù)的時(shí)候,我們根據(jù)表與表之間的關(guān)聯(lián)性來(lái)尋找對(duì)應(yīng)的數(shù)據(jù)
-- 我們查找 SMITH 的工作崗位的詳細(xì)信息
-- 先找到 SMITH
select ename from emp where ename = 'SMITH'
-- 找到 SMITH 的工作部門(mén)
select ename,deptno from emp where ename = 'SMITH'
-- 找到部門(mén) 20 的詳細(xì)信息
select * from dept where deptno = 20;
-- 使用笛卡爾積將兩張表拼接
select * from emp,dept;
-- 選擇有效的字段,emp表的 ename字段 ,deptno字段,dept表的全部字段
select emp.ename,emp.deptno,dept.* from emp,dept;
-- 只需要部門(mén)20,名字是SMITH
select e.ename,d.* from emp e,dept d where e.ename = 'SMITH' and d.deptno = 20; -- 笛卡爾積 select e.ename,d.* from emp e,dept d where e.ename = 'SMITH' and d.deptno = e.deptno; -- 等值連接
3.2 非等值連接查詢
連接兩個(gè)表時(shí)使用不等于運(yùn)算符來(lái)比較兩個(gè)表的列
-- 查找成績(jī)?cè)?0分以上,這門(mén)課的學(xué)分可以獲得,計(jì)算每個(gè)學(xué)生總學(xué)分和統(tǒng)計(jì)姓名
select s.*,m.*,c.* from student s,mark m,course c;
select * from student; select * from mark; select * from course;
-- 得到關(guān)聯(lián)字段
select s.*,m.*,c.* from student s,mark m,course c where s.sid = m.sid and m.cid = c.cid;
-- 不等值的條件
select s.*,m.*,c.* from student s,mark m,course c where s.sid = m.sid and m.cid = c.cid and cmark >= 60;
-- 去除重復(fù)數(shù)據(jù)
select sname,sum(cval) from student s,mark m,course c
where s.sid = m.sid and m.cid = c.cid and cmark >= 60
group by sname,s.sid ;
3.3 自連接
一張表當(dāng)多張表用
select a.*,b.* from dept a,dept b;
-- 查詢 emp 表中所有工資比部門(mén)平均工資高的員工信息
select * from emp;
select sal,ceil(avg(sal)) from emp group by deptno,sal having sal > avg(sal); -- 錯(cuò)誤 800 > 800/1
-- 連接兩張 emp 表
select e1.*,e2.* from emp e1,emp e2;
-- 拿到需要的字段 select e1.sal,e1.ename from emp e1,emp e2;
-- 等值連接
select e1.sal,e1.ename from emp e1,emp e2 where e1.deptno = e2.deptno;
-- 去除重復(fù)數(shù)據(jù)
select e1.sal,e1.ename,ceil(avg(e2.sal)) from emp e1,emp e2
where e1.deptno = e2.deptno
group by e1.deptno,e1.sal,e1.ename;
-- 添加條件
select e1.sal,e1.ename,ceil(avg(e2.sal)) from emp e1,emp e2
where e1.deptno = e2.deptno
group by e1.deptno,e1.sal,e1.ename having e1.sal > avg(e2.sal);
3.4 左外連接右外連接(left join,right join)
以左邊或者右邊的表為基準(zhǔn)表查詢數(shù)據(jù),如果沒(méi)有數(shù)據(jù)補(bǔ)null值,判斷時(shí)添加on使用等值連接
create table testA (
????????????????tid number,
????????????????A_name varchar2(10)
);
insert into testA values(1,'A');
insert into testA values(2,'B');
insert into testA values(3,'C');
????????create table testB (
????????????????????????tid number,
????????????????????????B_name varchar2(10)
);
insert into testB values(1,'A');
insert into testB values(2,'B');
insert into testB values(3,'C');
insert into testB values(4,'D');
-- 刪除表
DROP TABLE testA;
DROP TABLE testB;
select * from testA;
select * from testB;
-- 左外連接
select * from testA left join testB on testA.tid = testB.tid
-- 右外連接
select * from testA right join testB on testA.tid = testB.tid
3.5 內(nèi)連接(inner join)
當(dāng)我們想要將兩個(gè)或者多個(gè)表中的數(shù)據(jù)進(jìn)行連接時(shí)可以使用內(nèi)連接,通過(guò)一個(gè)或者多個(gè)關(guān)聯(lián)條件,它會(huì)返回兩個(gè)表中匹配到的行,也就是說(shuō)在連接表中存在匹配的行時(shí)才會(huì)返回結(jié)果
inner join 可以簡(jiǎn)寫(xiě)成 join
create table emp_test (
????????????????emp_no number,
????????????????emp_name varchar2(10),
????????????????dept_no number
);
insert into emp_test values(1,'張三',1);
insert into emp_test values(2,'李四',2);
insert into emp_test values(3,'王五',2);
insert into emp_test values(4,'趙六',3);
????????create table dept_test (
????????????????dept_no number,
????????????????dept_name varchar2(10)
);
insert into dept_test values(1,'人事部');
insert into dept_test values(2,'技術(shù)部');
insert into dept_test values(3,'財(cái)務(wù)部');
select * from emp_test; select * from dept_test;
-- 查詢員工的姓名和所在部門(mén)的名稱(chēng)
select e.emp_name,d.dept_name from emp_test e,dept_test d
where d.dept_no = e.dept_no; -- 笛卡爾積
select e.emp_name,d.dept_name from emp_test e inner join dept_test d on d.dept_no = e.dept_no; -- 內(nèi)連接
-- 查詢每個(gè)學(xué)生的姓名和平均分
select s.sid,ceil(avg(cmark)) from student s, mark m
where s.sid=m.sid group by s.sid -- 笛卡爾積
select s.sid ,ceil(avg(cmark)) from student s inner join mark m on m.sid=s.sid group by s.sid -- 內(nèi)連接
比較笛卡爾積和內(nèi)連接:
內(nèi)連接:只返回滿足連接條件的結(jié)果集,可以過(guò)濾數(shù)據(jù)笛卡爾積:只是單純的連接兩個(gè)表的行,不會(huì)過(guò)濾出數(shù)據(jù)
優(yōu)勢(shì)
數(shù)據(jù)過(guò)濾:內(nèi)連接會(huì)根據(jù)關(guān)聯(lián)條件來(lái)過(guò)濾數(shù)據(jù),只返回相關(guān)的行,減少了數(shù)據(jù)的查詢速度查詢效率:內(nèi)連接的查詢效率高于笛卡爾積資源占用:內(nèi)連接只返回有效數(shù)據(jù),所以資源占用小
舉例
create table customers (
????????????????cid number,
????????????????cname varchar2(10),
????????????????clocal varchar(100)
);
insert into customers values(1,'張三','南京');
insert into customers values(2,'李四','揚(yáng)州');
insert into customers values(3,'王五','徐州');
insert into customers values(4,'趙六','蘇州');
create table orders (
????????????????oid number,
????????????????cid number,
????????????????odate varchar2(10)
);
insert into orders values(101,1,'07-01');
insert into orders values(202,2,'07-02');
insert into orders values(303,3,'07-03');
insert into orders values(404,4,'07-04');
select * from customers; select * from orders;
-- 返回匹配數(shù)據(jù)
select cname,clocal,oid,odate from customers inner join orders on customers.cid = orders.cid; select cname,clocal,oid,odate from customers inner join orders就是笛卡爾積的
select cname,clocal,oid,odate from customers,orders
所以相對(duì)于笛卡爾積來(lái)說(shuō),少了一步,所以查詢時(shí)間肯定是比笛卡爾積塊
select cname,clocal,oid,odate from customers,orders where customers.cid = orders.cid;
4 高級(jí)查詢、開(kāi)窗函數(shù)、分頁(yè)查詢、TopN查詢
4.1 隨機(jī)查詢
dbms_random.value()
-- 產(chǎn)生 0 ~ 1 之間的隨機(jī)數(shù),可以為0,不能為1
select dbms_random.value() from dual;
-- 產(chǎn)生 1 ~ 11 之間的隨機(jī)數(shù)
select dbms_random.value(1,11) from dual;
-- 產(chǎn)生 1 ~ 10 之間的隨機(jī)整數(shù),含有10
select trunc(dbms_random.value(1,11),0) from dual;
-- 生成一個(gè)隨機(jī)小寫(xiě)字母97 ~ 122
select chr(trunc(dbms_random.value(97,123),0)) from dual;
-- 隨機(jī)返回學(xué)生表的五條數(shù)據(jù) -- 得到一張順序被打亂的新表
select * from student order by dbms_random.value();
-- 使用 rownum 返回五條數(shù)據(jù)
select rownum r,s.* from (select * from student order by dbms_random.value()) s where rownum <= 5
4.2 子查詢
4.2.1 什么是子查詢?
從一個(gè)表中查出來(lái)的部分?jǐn)?shù)據(jù)當(dāng)作另一個(gè)表的查詢條件,分為單行子查詢和多行子查詢
4.2.2 單行子查詢
查詢出來(lái)的結(jié)果只有一行,精確的匹配某個(gè)值
-- 查詢工資最高的員工 -- 找到最高的工資(5000)
select max(sal) from emp;
-- 拿最高的工資找人,最高的工資(5000)當(dāng)作條件
select ename,sal from emp where sal = (select max(sal) from emp)
-- 查詢學(xué)生,年齡比學(xué)號(hào)10005號(hào)學(xué)生大的其他學(xué)生的姓名
-- 找到 10005 號(hào)學(xué)生的年齡(21)
select sage from student where sid = 10005;
-- 比 21 大的其他學(xué)生的姓名
select sname from student where sage > 21;
select sname from student where sage > ( select sage from student where sid = 10005);
4.2.3 多行子查詢
使用 in any all 三種運(yùn)算符
4.2.3.1 in 運(yùn)算符
用于判斷某個(gè)值是否在子查詢返回的結(jié)果集中,在子查詢中返回的結(jié)果只要有一個(gè)值等于外層查詢中的某個(gè)值,就會(huì)返回結(jié)果
1. 找到對(duì)應(yīng)的值
2. 作為條件,里層和外層的值要對(duì)應(yīng)
-- 找出所有男生的成績(jī)
-- 先找到所有男生
select sid from student where ssex = '男';
-- 找出所有男生的成績(jī)
select * from mark; select sid,cmark from mark where sid in (select sid from student where ssex = '男');
4.2.3.2 多行子查詢是可以無(wú)限嵌套的
-- 找出所有男生的成績(jī)
select sid,cmark from mark where sid in (select sid from student where ssex = '男');
-- 找出所有男生的成績(jī)所對(duì)應(yīng)的科目
select * from course;
select * from course
where cid in (
select cid from mark
where sid in (
select sid from student
where ssex = '男'))
-- 找出科目所對(duì)應(yīng)的老師
select * from teacher
where tid in (
select tid from course
where cid in (
select cid from mark
where sid in (
select sid from student where ssex = '男')))
4.2.3.3 any運(yùn)算符
用于比較外層查詢中的某個(gè)值與子查詢返回的結(jié)果集中的任意一個(gè)值是否相等,在子查詢中返回的結(jié)果只要有一個(gè)值與外層查詢中的某個(gè)值相等,返回結(jié)果
-- 查詢年齡大于江蘇任意一個(gè)學(xué)生年齡的其他地區(qū)的學(xué)生信息
-- 查找江蘇學(xué)生的年齡
select sage from student where snativeplace = '江蘇';
-- 查詢比江蘇地區(qū)最小年齡大的學(xué)生的其他地區(qū)的學(xué)生信息
select sname,snativeplace,sage from student
where sage > any (select sage from student where snativeplace = '江蘇')
4.2.3.4 all運(yùn)算符
用于比較外層查詢中的某個(gè)值與子查詢返回的結(jié)果集中的全部值是否相等,在子查詢中返回的結(jié)果集中的所有值都與外層查詢中的某個(gè)值相等,才會(huì)返回結(jié)果
-- 查詢年齡大于江蘇地區(qū)所有學(xué)生年齡的其他地區(qū)的學(xué)生信息
select sname,snativeplace,sage from student
where sage > all (select sage from student where snativeplace = '江蘇') and snativeplace != '江蘇';
4.3 開(kāi)窗函數(shù)
4.3.1 開(kāi)窗函數(shù)over()
語(yǔ)法:over(值1 order by 值2),根據(jù)值1,進(jìn)行區(qū)分,再分區(qū)內(nèi)按照值2進(jìn)行排序注意:over函數(shù)一般不單獨(dú)使用,會(huì)和關(guān)鍵字進(jìn)行配合
4.3.2 常用關(guān)鍵字
row_number: 用于為結(jié)果集中的每一行分配唯一的序號(hào)。這個(gè)序號(hào)是根據(jù) order by 子句定義的排序順序來(lái)分配的。rank:用于為結(jié)果集中的每一行分配一個(gè)排名。如果有多個(gè)行具有相同的值,則被分配相同的排名,下一個(gè)排名將被跳過(guò)dense_rank:與rank相似,但是具有多行相同值,被分配相同的排名,并且下一個(gè)排名不會(huì)被跳過(guò)lead:用于獲取結(jié)果中當(dāng)前行之后的第n行值??梢允褂?partition by 子句將結(jié)果集分成多個(gè)分區(qū)sum:用于計(jì)算指定列的總和??梢允褂?group by 子句將結(jié)果集分組lag:用于獲取結(jié)果中當(dāng)前行之前的第n行值。
4.3.2.1 row_numbe關(guān)鍵字的使用
-- 查詢學(xué)生分?jǐn)?shù)信息,并按照每個(gè)人的分?jǐn)?shù)進(jìn)行排序
select m.*,row_number()over(partition by m.sid order by m.cmark desc) 排名 from mark m
?-- 每個(gè)學(xué)生 前三名 的成績(jī)
select * from ( select m.*,row_number()over(partition by m.sid
order by m.cmark desc) paiming from mark m) where paiming <= 3;
-- 查詢學(xué)生表,跳過(guò)表中的偶數(shù)行
-- 根據(jù) sid 分配
select row_number()over(order by sid) num,s.* from student s
-- 跳過(guò)偶數(shù)行
select * from (
select row_number()over(order by sid) num,s.* from student s)
where mod(num,2) = 1;
4.3.2.2 rank關(guān)鍵字的使用
-- 查詢每個(gè)學(xué)生的成績(jī),并且為每個(gè)學(xué)生計(jì)算排名
select m.*,rank()over(partition by m.sid order by m.cmark desc) paiming from mark m
?-- 查詢每個(gè)學(xué)生的成績(jī),計(jì)算每個(gè)學(xué)生的排名,并列排名并且合成一個(gè)位置
select m.*,dense_rank()over(partition by m.sid order by m.cmark desc) paiming from mark m
4.3.2.3 max和min的使用
-- 查詢最大年齡和最小年齡
select distinct(max(sage)over()),min(sage)over() from student;
4.3.2.4 sum的使用
-- 求所有學(xué)生的年齡的連續(xù)求和、總合
-- 一共18組,總合 366
select sum(sage) over(order by sid) 連續(xù)求和,sum(sage) over() 總和 from student;
?
-- 分班級(jí)給學(xué)生的年齡求和、連續(xù)求和、總和,20歲以上的參與計(jì)算
select sclass,sname,sage, sum(sage)over(partition by sclass order by sid) 連續(xù)求和, sum(sage)over(partition by sclass) 總和
from student
where sage >= 20;
4.3.2.5 lag和lead關(guān)鍵字的使用
select sname,sage,
lead(sage) over(order by sage) 下一行,
lag(sage) over(order by sage) 上一行
from student
?
?-- 查詢第三行以下的數(shù)據(jù) row_number,rownum
select sname,sage,
????????row_number()over(order by sage desc) row_num,
????????lead(sage) over(order by sage desc) 下一行
????????from student
-- 子查詢
select *
????????from ( select sname,sage,
????????????????row_number()over(order by sage desc) row_num,
????????????????lead(sage) over(order by sage desc) 下一行
????????????????from student)
where row_num > 3;
4.4 分頁(yè)查詢
思考:如果表數(shù)據(jù)量特別大,想要一次性展現(xiàn)給用戶,頁(yè)面加載數(shù)據(jù)很多,導(dǎo)致查詢速度很慢,體驗(yàn)很差,如何解決
解決:使用分頁(yè)查詢進(jìn)行分頁(yè)展示
-- 語(yǔ)法 -- 每頁(yè)展示 m 條數(shù)據(jù) 查詢第 n 頁(yè)的數(shù)據(jù)
select * from (
????????select rownum r,t1.* from table1 t1(需要分頁(yè)的表)
????????where rownum <= m * n)t2
????????where r > m * n - m
-- 查詢學(xué)生表的 10 ~ 15 行的數(shù)據(jù)
-- 每頁(yè)分 5 條數(shù)據(jù),查詢 第 3 頁(yè)的數(shù)據(jù)
-- m = 5,n = 3
select * from (
????????select rownum r,s.* from student s
????????where rownum <= 15)t
where r > 10;
4.5 TopN查詢
是一種查詢語(yǔ)句,可以返回指定數(shù)據(jù)集中的前N個(gè)符合條件的記錄,通常,TopN用在數(shù)據(jù)分析和業(yè)務(wù)決策很有效
比如:mark表存儲(chǔ)了學(xué)生的分?jǐn)?shù),我們可以使用TopN來(lái)返回前N名分?jǐn)?shù)最高的學(xué)生記錄
4.5.1 rownum
這是Oracle當(dāng)中的一個(gè)“偽列”,它按照查詢結(jié)果集中的行號(hào)為每一行分配一個(gè)唯一的值,我們可以使用rownum實(shí)現(xiàn)
注意:在使用rownum的時(shí)候,我們必須放在子查詢中,并在外部查詢中進(jìn)行限制,否則會(huì)出現(xiàn)錯(cuò)誤的結(jié)果
4.5.1.1.rownum對(duì)于等于某個(gè)值的查詢條件
我們想使用rownum查詢第一行數(shù)據(jù),rownum = 1,查詢第二行不能使用 rownum = 2,沒(méi)有結(jié)果,rownum無(wú)法使用 = 連接大于 1 的數(shù),如果你想實(shí)現(xiàn) rownum = 2 這種效果,需要使用子查詢,rownum要取別名
--查詢學(xué)生表的第一條數(shù)據(jù)
select rownum r,student.* from student
where rownum = 1;
--查詢學(xué)生表的第六條數(shù)據(jù)
select * from (select rownum r,s.* from student s)
where r =6;
4.5.1.2.rownum對(duì)于大于某個(gè)值的查詢條件
查詢大于某值的記錄的時(shí)候,rownum > n(n是自然數(shù))一般這種情況也是不行的,依然使用子查詢
-- 查詢第一行以后的數(shù)據(jù)
select rownum r,student.* from student
where rownum > 1;
-- 沒(méi)數(shù)據(jù) select * from (
select rownum r,s.* from student s)
where r > 1;
4.5.1.3.rownum對(duì)于小于某個(gè)值的查詢條件
可以直接使用 rownum < n,用來(lái)查詢前幾行的數(shù)據(jù)
-- 查詢前十行的數(shù)據(jù)
select rownum r,student.* from student
where rownum <= 10;
4.5.1.4.rownum查詢某個(gè)區(qū)間的數(shù)據(jù)
使用子查詢
-- 查詢年齡從高到低,第 5 ~ 8 行的數(shù)據(jù) -- 按照年齡排序
select * from student order by sage desc
-- 獲取每一行
select rownum r,s.* from (
select * from student order by sage desc) s
-- 查找 5 ~ 8 的數(shù)據(jù)
select * from (
select rownum r,s.* from (
select * from student order by sage desc) s)
where r between 5 and 8;
4.5.1.5.rownum和order by
rownum 是獲取數(shù)據(jù)的時(shí)候產(chǎn)生的序列號(hào)使用 order by 會(huì)打亂排序rownum 想獲取排序后的內(nèi)容,也要使用子查詢,將排好的查詢,作為子查詢重新查詢order by 是用來(lái)排序查詢結(jié)果,只能升序或者降序,按照一個(gè)或者多個(gè)排序,不能指定區(qū)間(where)rownum 是一個(gè)偽列,只是用來(lái)限制查詢結(jié)果的行數(shù)
5 事務(wù)、視圖、數(shù)據(jù)類(lèi)型、約束
5.1 什么是事務(wù)?
數(shù)據(jù)庫(kù)操作的一個(gè)邏輯單位,一般由一個(gè)或者多個(gè)數(shù)據(jù)庫(kù)操作組成。事務(wù)中的操作要么全部執(zhí)行,要么都不執(zhí)行,要么全部成功提交,要么全部失敗并回滾,保證數(shù)據(jù)的一致性和完整性
5.2 事務(wù)控制
只要是DML(增刪改)操作會(huì)自動(dòng)啟動(dòng)事務(wù)。一旦開(kāi)始了事務(wù),所有的增刪改操作都會(huì)被納為是一個(gè)事務(wù),直到事務(wù)被提交或回滾
特點(diǎn):
一個(gè)事務(wù)內(nèi)的所有操作一起被提交或回滾提交或回滾后的其他事務(wù)與之前的事務(wù)沒(méi)有任何聯(lián)系當(dāng)事務(wù)被提交后,其他人才能看到事務(wù)提交后的結(jié)果
注意:
如果事務(wù)沒(méi)有提交或回滾,其他人再次嘗試執(zhí)行相同的事務(wù)操作會(huì)導(dǎo)致鎖定現(xiàn)象,無(wú)法完成事務(wù)。這時(shí)一旦事務(wù)上了鎖,必須等待鎖釋放才能繼續(xù)執(zhí)行相同的操作
5.3 事務(wù)控制的操作
5.3.1 永久保存 commit
-- 插入數(shù)據(jù)
insert into cour2 values(105,'歷史',64,1005);
-- 更新數(shù)據(jù)
update cour2 set cid = 1001 where cname = '科學(xué)';
-- 插入數(shù)據(jù)
insert into cour2 values(106,'物理',64,1006);
-- 提交操作,并永久保存
commit;
5.3.2 回滾 rollback
-- 可以回滾到事務(wù)開(kāi)始前的樣式
rollback;
-- 創(chuàng)建保存點(diǎn)
savepoint a;
-- 執(zhí)行事務(wù)操作
delete from cour where tid = 1001
-- 回滾到保存點(diǎn)
rollback to a
5.4 事務(wù)的特性
ACID,db-01
5.4.1 原子性
-- 開(kāi)啟事務(wù)
BEGIN;
-- 插入數(shù)據(jù)
?insert into customertype (cid,ctype,explain) values(4,'銅卡會(huì)員','消費(fèi)在30000元以上');
--更新數(shù)據(jù)
update customertype set ctype = '一般客戶' where cid = 1;
-- 事務(wù)結(jié)束
commit;
5.4.2 一致性
-- 開(kāi)啟事務(wù)
BEGIN
-- 插入數(shù)據(jù)
insert into customertype (cid,ctype,explain) values(5,'黑卡會(huì)員','消費(fèi)在70000元以上');
-- 事務(wù)結(jié)束
commit;
END;
-- 查詢數(shù)據(jù)
select * from customertype;
5.4.3 隔離性
-- 開(kāi)啟事務(wù)A
BEGIN TRANSACTION
-- 在事務(wù)A 中修改數(shù)據(jù)
UPDATE customertype SET ctype = 'yiban客戶' WHERE cid = 1;
commit;
END;
-- 在事務(wù)B 中 修改數(shù)據(jù)
BEGIN TRANSACTION
update customertype set ctype = '普通客戶' where cid = 1;
commit;
END;
-- 在事務(wù)A中查詢數(shù)據(jù)
select * from customertype;
commit;
-- 在事務(wù)B中查詢數(shù)據(jù)
select * from customertype;
commit;
5.4.4 持久性
-- 開(kāi)啟事務(wù)
BEGIN
-- 插入數(shù)據(jù)
insert into customertype (cid,ctype,explain) values(6,'至尊會(huì)員','消費(fèi)在100000元以上');
-- 事務(wù)結(jié)束
commit;
END;
-- 插入完 數(shù)據(jù)一直存在
select * from customertype;
5.5 數(shù)據(jù)共享
臟讀(Drity Read):一個(gè)事務(wù)讀取到另一個(gè)事務(wù)尚未提交的數(shù)據(jù)。 事務(wù) A 讀取事務(wù) B 更新的數(shù)據(jù),然后 B 回滾(RollBack)操作,那么 A 讀取到的數(shù)據(jù)是臟數(shù)據(jù)。
不可重復(fù)讀(Non-repeatable read):一個(gè)事務(wù)中兩次讀取的數(shù)據(jù)的內(nèi)容不一致。 事務(wù) A 多次讀取同一數(shù)據(jù),事務(wù) B 在事務(wù) A 多次讀取的過(guò)程中,對(duì)數(shù)據(jù)作了更新并提交,導(dǎo)致事務(wù) A 多次讀取同一數(shù)據(jù)時(shí),結(jié)果 不一致。
幻讀(Durability ):一個(gè)事務(wù)中兩次讀取的數(shù)據(jù)量不一致。 系統(tǒng)管理員 A 將數(shù)據(jù)庫(kù)中所有學(xué)生的成績(jī)從具體分?jǐn)?shù)改為 ABCDE 等級(jí),但是系統(tǒng)管理員 B 就在這個(gè)時(shí)候插入了一條具體分?jǐn)?shù)的記錄,當(dāng)系統(tǒng)管理員 A 改結(jié)束后發(fā)現(xiàn)還有一條記錄沒(méi)有改過(guò)來(lái),就好像發(fā)生了幻覺(jué)一樣,這就叫幻讀。
不可重復(fù)讀的和幻讀很容易混淆,不可重復(fù)讀側(cè)重于修改,幻讀側(cè)重于新增或刪除。 解決不可重復(fù)讀的問(wèn)題只需鎖住滿足條件的行,解決幻讀需要鎖表
事務(wù)的隔離級(jí)別
SQL 標(biāo)準(zhǔn)定義了四個(gè)隔離級(jí)別:
READ-UNCOMMITTED(讀取未提交):?最低的隔離級(jí)別,允許讀取尚未提交的數(shù)據(jù)變更READ-COMMITTED(讀取已提交):?允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù)REPEATABLE-READ(可重復(fù)讀):?對(duì)同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改SERIALIZABLE(可串行化):?最高的隔離級(jí)別,完全服從ACID的隔離級(jí)別。所有的事務(wù)依次逐個(gè)執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾
隔離級(jí)別 臟讀 不可重復(fù)讀 幻讀 READ-UNCOMMITTED(讀取未提交) √ √ √ READ-COMMITTED(讀取已提交) × √ √ REPEATABLE-READ(可重復(fù)讀) × × √ SERIALIZABLE(可串行化) × × ×
5.6 視圖
5.6.1 什么是視圖?
是數(shù)據(jù)庫(kù)中一種虛擬的表,它由一個(gè)人或者多個(gè)的查詢結(jié)果定義出來(lái)的,視圖并不存儲(chǔ)實(shí)際的數(shù)據(jù),而是在訪問(wèn)時(shí)動(dòng)態(tài)生成結(jié)果。
優(yōu)點(diǎn):
可以封裝查詢操作,提供簡(jiǎn)化、重用、和安全性等優(yōu)勢(shì)使用視圖可以將復(fù)雜的邏輯包裹起來(lái),以便從視圖里直接檢索數(shù)據(jù),就不用再次書(shū)寫(xiě)查詢語(yǔ)句
5.6.2 創(chuàng)建視圖
-- 語(yǔ)法
create view 視圖名 as
條件查詢語(yǔ)句
-- 創(chuàng)建視圖 保存高工資的員工數(shù)據(jù)
create view highsal as
select empno,ename,job,sal
from emp where sal > 2500;
-- 如果沒(méi)有權(quán)限,切換到 sys 用戶,授權(quán)
grant create view to scott;
-- 查看視圖
select * from highsal;
-- 更新視圖
update highsal set sal = sal * 1.1
-- 插入視圖
insert into highsal(empno,ename,job,sal)
values (7788,'Jack','SALESMAN',3000)
-- 刪除視圖
drop view highsal
5.6.3 表與視圖的區(qū)別
表:
數(shù)據(jù)庫(kù)中實(shí)際存儲(chǔ)的數(shù)據(jù)對(duì)象,具有固定的結(jié)構(gòu)和命名表由行和列組成,可以直接存儲(chǔ)數(shù)據(jù)表可以包含索引、約束、觸發(fā)器等數(shù)據(jù)庫(kù)對(duì)象對(duì)表可以執(zhí)行數(shù)據(jù)的增刪改查
視圖
視圖是數(shù)據(jù)庫(kù)中虛擬的表,是基于查詢結(jié)果出現(xiàn)的不存儲(chǔ)實(shí)際的數(shù)據(jù),僅在動(dòng)態(tài)生成結(jié)果視圖可以簡(jiǎn)化查詢的操作,方便我們更快找到查詢結(jié)果可以做到和表一樣的操作
主要區(qū)別
存儲(chǔ)方式:表存儲(chǔ)實(shí)際的數(shù)據(jù),視圖不是結(jié)構(gòu)定義:表是行和列的定義,視圖是查詢結(jié)果的定義數(shù)據(jù)保持:表一旦數(shù)據(jù)完成增刪改查永久保存,視圖只有在訪問(wèn)時(shí)菜生成數(shù)據(jù)數(shù)據(jù)修改:表的修改是永久的,視圖只讀的
5.7 數(shù)據(jù)類(lèi)型
5.7.1 按照類(lèi)型分類(lèi)
1.字符串類(lèi)型:char、varchar2、clob,用于存儲(chǔ)文本數(shù)據(jù),char和varchar2分別是定長(zhǎng)和變長(zhǎng)的字符串類(lèi)型,clob是用于存儲(chǔ)大量文本數(shù)據(jù)的類(lèi)型
char:定長(zhǎng),10,helloxxxxx
varchar2:變長(zhǎng),10,hello
2.數(shù)值類(lèi)型:number,用于存儲(chǔ)數(shù)據(jù)類(lèi)型,包括整數(shù)、小數(shù)等??梢灾付ň群头秶?/p>
3.日期類(lèi)型:date、timestamp,用于存儲(chǔ)日期和時(shí)間。date可以精確到秒,timestamp可以精確到毫秒
4.布爾類(lèi)型:boolean,只有兩個(gè)數(shù)據(jù)類(lèi)型,一個(gè)是true一個(gè)是false
5.二進(jìn)制類(lèi)型:blob,存儲(chǔ)圖片、音頻
6.不常用的:rowid、raw、long
5.7.2 數(shù)據(jù)類(lèi)型注意事項(xiàng)
1.char 類(lèi)型是固定長(zhǎng)度,處理速度比varchar2快,字符填充不滿的時(shí)候,需要使用 trim 把兩邊的空格去掉
2.varchar2一般用于英文和數(shù)字,nvarchar2一般用于中文和其他字符,我們通常還是使用varchar2
3.varchar2是可變長(zhǎng)度,放入幾個(gè)字符就是幾個(gè)字符,不能超過(guò)設(shè)定的字符
4.number(4,2)整數(shù)占4位小數(shù)占兩位,如果小數(shù)位數(shù)多,會(huì)自動(dòng)四舍五入截取指定的位數(shù)
5.number默認(rèn)是38位,放入 99.994 可以,99.995 不行
5.7.3 DDL
數(shù)據(jù)庫(kù)定義語(yǔ)句 5.7.4 常用關(guān)鍵詞
create:創(chuàng)建表、視圖、索引alter:修改表、列、約束drop:刪除表、視圖、索引revoke:撤銷(xiāo)其他角色對(duì)某個(gè)對(duì)象的訪問(wèn)權(quán)限
5.7.5 創(chuàng)建表create table ...
create table 表名(
????????字段1 類(lèi)型(長(zhǎng)度),
????????字段2 類(lèi)型(長(zhǎng)度),
????????....
);
-- 語(yǔ)法建表
create table stu(
????????id number(5),
????????name varchar2(50),
????????gender char(3),
????????tel number(11)
);
-- 子查詢建表
create table 表1 as select 字段 from 表2
-- 表1 根據(jù) 表2 創(chuàng)建的,兩個(gè)表一模一樣
create table stu1 as select * from student;
5.7.6 增加字段 alter ... add
alter table 表名 add 字段 類(lèi)型;
-- 給 stu 表增加一個(gè) age 字段
alter table stu add age number(3);
5.7.7 修改字段 alter modify / rename column
modify:修改數(shù)據(jù)類(lèi)型
rename column:修改字段名
-- 修改 number 為 varchar2
alter table stu modify id varchar2(10)
-- 修改 id 為 sid
alter table stu rename column id to sid
5.7.7.1 刪除字段 alter drop
-- 刪除 stu 表的 tel 字段
alter table stu drop column tel;
5.7.7.2 刪除表 drop
-- 刪除 stu1 表
drop table stu1;
5.7.7.3 重命名表 rename
-- 修改 stu 表名為 sttu
rename stu to sttu
練習(xí)
創(chuàng)建商品表,商品表中含有商品編號(hào)、商品名稱(chēng)、商品價(jià)格、商品說(shuō)明這幾個(gè)字段,創(chuàng)建完成以后,需要增加商品數(shù)量這個(gè)字段
表名:shop
商品編號(hào):sp_id
商品名稱(chēng):sp_name
商品價(jià)格:sp_price
商品說(shuō)明:sp_text
商品數(shù)量:sp_num
create table shop (
????????sp_id number(10),
????????sp_name varchar2(50),
????????sp_price number(8,2),
????????sp_text varchar2(200)
);
alter table shop add sp_num number(20)
select * from shop
5.7.8 DML
數(shù)據(jù)庫(kù)操作語(yǔ)言
常用關(guān)鍵字
select:查詢
insert:插入
update:更新
delete:刪除
merge:合并
upsert:更新數(shù)據(jù),如果數(shù)據(jù)存在則更新,不存在則插入
replace:替換
truncate(trunce):清空
5.7.8.1 插入
值要與字段對(duì)應(yīng),并且符合字段的屬性
-- 可以缺少值,值與字段相對(duì)應(yīng)
insert into 表名(字段1,字段2,...) values (值1,值2,...)
-- 不可以缺少值,有多少字段,就有多少值
insert into 表名 values(值1,值2,...)
-- 子查詢插入數(shù)據(jù)
insert into 表1 select 字段 from 表2 -- 表2的數(shù)據(jù)插入給表1
-- 舉例
-- 全字段插入
insert into shop(sp_id,sp_name,sp_price,sp_text,sp_num)
values(10000004,'男士運(yùn)動(dòng)鞋',199.99,'男士網(wǎng)面夏季鞋',9999)
-- 不使用字段名插入
insert into shop values(10000002,'女士運(yùn)動(dòng)鞋',199.99,'女士透氣夏季運(yùn)動(dòng)鞋') -- 報(bào)錯(cuò),因?yàn)槿鄙僦?insert into shop values(10000002,'女士運(yùn)動(dòng)鞋',199.99,'女士透氣夏季運(yùn)動(dòng)鞋',9999)
-- 全字段插入時(shí)可以選擇性插入數(shù)據(jù),沒(méi)有選擇的字段為 null 值
insert into shop(sp_id,sp_name,sp_price,sp_text)
values(10000003,'男士運(yùn)動(dòng)鞋',199.99,'男士網(wǎng)面夏季鞋')
-- 子查詢插入數(shù)據(jù)
insert into sttu select sid,sname,ssex,sage from student;
5.7.8.2 更新
-- 指定條件修改數(shù)據(jù)
update 表名 set 字段 = 數(shù)據(jù) where 條件 -- 如果不指定條件,默認(rèn)全修改
-- 修改張三的年齡為 22 歲
update sttu set age = 22 where name = '蕭瑾';
-- 修改全部人的性別為 女
update sttu set gender = '女'
5.7.8.3 刪除
-- 指定條件刪除數(shù)據(jù)
delete from 表名 where 條件
-- 刪除李四的數(shù)據(jù)
delete from sttu where name = '李四'
-- 不加條件 默認(rèn)全刪除,和 truncate 一樣的效果
delete from sttu truncate table sttu
5.8 約束
對(duì)插入的數(shù)據(jù)進(jìn)行限制,比如:在姓名這個(gè)字段內(nèi)不能為空、性別只能設(shè)置為男或者女、手機(jī)號(hào)碼必須是11位
5.8.1 常見(jiàn)約束
主鍵約束 - primary key:用于唯一標(biāo)識(shí)表中每一行記錄的列,保證了該列的數(shù)據(jù)不重復(fù)并且不能為空唯一約束 - unique:保證該列的值不重復(fù),但是可以為空外鍵約束 - foreign key :將一個(gè)表中的列與另一個(gè)表中的列建立關(guān)聯(lián),保證了數(shù)據(jù)的一致性和完整性選擇約束 - check:在插入或者更新記錄時(shí),檢查指定列的值是否符合指定條件。插入的數(shù)據(jù),必須選擇范圍里面的非空約束 - not null:保證該列的值不能為空
5.8.2 添加約束
5.8.2.1 建表時(shí)添加約束
create table employees(
????????employee_id number(5) primary key,
????????first_name varchar2(50) not null,
????????last_name varchar2(50) not null,
????????hire_date date not null,
????????salary number(10,2)
);
5.8.2.2 alter添加約束
-- 給 sid 添加約束
alter table student add primary key(sid)
-- 修改表字段時(shí)添加約束
alter table sttu modify name char(50) not null
-- 使用 constraint 添加唯一約束
alter table sttu add constraint sttu_uq unique(name)
-- 修改表數(shù)據(jù)的時(shí)候使用 constraint 添加選擇約束
alter table student add constraint ssex_check check(ssex in('男','女'))
-- 使用 alter 添加外鍵約束 和 級(jí)聯(lián)刪除(on delete cascade)
alter table mark
add constraint mk_su foreign key(sid) references student(sid) on delete cascade
alter table 目標(biāo)表
add constraint 外鍵名 foreign key(目標(biāo)字段) references 參考表(參考字段) on delete cascade
5.8.2.3 外鍵約束
在兩個(gè)表之間建立連接,可以是一個(gè)列或者是多個(gè)列,一個(gè)表可以有一個(gè)或者多個(gè)外鍵
a,b兩張表,a是主表,b是副表,b表的外鍵指向a表
如果要添加信息,必須先在a中添加,再去b添加,刪除是相反的,先刪除b再刪除a
create table teach(
tid number primary key,
tname varchar2(50) not null,
tsex char(3) not null check(tsex in ('男','女')),
tphone number(11) not null unique
);
insert into teach values(1001,'張三','男',12345678910);
insert into teach values(1002,'李四','女',12345678911);
insert into teach values(1003,'王五','男',12345678912);
insert into teach values(1004,'趙六','女',12345678913);
select * from teach;
create table cour(
cid number primary key,
cname varchar2(50),
ctime number,
tid number,
constraint fkey_tid foreign key (tid) references teach(tid)
);
select * from cour
-- 如果關(guān)聯(lián)的主表中沒(méi)有該 1005 tid 則數(shù)據(jù)插入失敗
insert into cour values(101,'語(yǔ)文',64,1005) -- 失敗
insert into cour values(101,'語(yǔ)文',64,1001) -- 成功
-- 外鍵刪除 -- 先刪除主表,報(bào)錯(cuò)
delete from teach where tid = 1001
-- 應(yīng)該先刪除副表
delete from cour where tid = 1001
-- 再刪除主表
delete from teach where tid = 1001
5.8.2.4 級(jí)聯(lián)刪除
當(dāng)一個(gè)表的數(shù)據(jù)被刪除時(shí),與之相關(guān)聯(lián)的其他表中的記錄也會(huì)被自動(dòng)刪除的操作,這種刪除操作可以通過(guò)外鍵約束中的 on delete cascade 來(lái)實(shí)現(xiàn)
通常用于確保數(shù)據(jù)的一致性和完整性,可以同時(shí)刪除多個(gè)相關(guān)記錄
一般都是創(chuàng)建外鍵的時(shí)候創(chuàng)建級(jí)聯(lián)刪除,很少單獨(dú)指定
create table cour1(
cid number primary key,
cname varchar2(50),
ctime number,
tid number,
constraint fkey_tid1 foreign key (tid) references teach(tid) on delete cascade
);
insert into cour1 values(101,'語(yǔ)文',64,1001);
insert into cour1 values(102,'數(shù)學(xué)',64,1002);
insert into cour1 values(103,'英語(yǔ)',64,1003);
select * from cour1
-- 可以直接刪除主表內(nèi)容,會(huì)連帶著副表的內(nèi)容也刪除
delete from teach where tid = 1001
5.8.2.5 刪除約束
-- 刪除主鍵約束
alter table sttu drop primary key
-- 按照約束名刪除
alter table sttu drop constraint sttu_uq
-- 如果要?jiǎng)h除唯一、檢查、外鍵,需要添加 constraint 約束名
alter table sttu drop constraint SSEX_CHK
-- 去除非空
alter table sttu modify name varchar2(50) null
6 索引、序列、PLSQL
6.1 什么是索引?
索引是在數(shù)據(jù)庫(kù)中用于加快檢索速度的數(shù)據(jù)結(jié)構(gòu)。類(lèi)似于書(shū)本的目錄
為什么要用索引?
加快檢索的時(shí)間:數(shù)據(jù)庫(kù)允許系統(tǒng)直接定位到包含特定值的行,無(wú)需掃描整個(gè)表提升查詢的性能:因?yàn)橛辛怂饕诓樵兡承┨囟ㄖ禃r(shí)可以通過(guò)索引快速查詢支持唯一約束:通過(guò)唯一列上創(chuàng)建唯一索引,可以卻表表中的值是唯一的優(yōu)化連接操作:作表之間的連接查詢時(shí),索引可以加快連接的速度,在連接字段上創(chuàng)建索引即可加速分組和排序:索引可以在執(zhí)行聚合函數(shù)和排序時(shí)提供更快的結(jié)果獲取內(nèi)容的速度:數(shù)據(jù)庫(kù)可以按照索引的順序來(lái)讀取數(shù)據(jù),避免臨時(shí)表的創(chuàng)建和額外的排序操作
6.2 訪問(wèn)數(shù)據(jù)庫(kù)的方式
6.2.1 Oracle
順序訪問(wèn):全表掃描,在沒(méi)有索引或者不滿足創(chuàng)建索引的條件時(shí),回對(duì)整個(gè)表進(jìn)行掃描,逐個(gè)獲取數(shù)據(jù)索引訪問(wèn):是通過(guò)遍歷索引來(lái)快速定位和查找符合條件的數(shù)據(jù)覆蓋索引:是一種特殊的索引訪問(wèn)方式,當(dāng)查詢只需要從索引中獲取數(shù)據(jù)時(shí),可以直接利用覆蓋索引,無(wú)需訪問(wèn)實(shí)際的行數(shù)
6.2.2 索引的分類(lèi)
B-Tree:B樹(shù)索引,使用一種多層次的平衡樹(shù)結(jié)構(gòu)唯一索引:確保索引列中的值是唯一的,可以通過(guò)主鍵約束來(lái)自動(dòng)創(chuàng)建,也可以手動(dòng)創(chuàng)建聚簇索引:按照表的物理順序來(lái)存儲(chǔ)數(shù)據(jù)的索引,按照索引的鍵值排序,并且與索引的結(jié)構(gòu)相關(guān)聯(lián),一個(gè)表只能有一個(gè)聚簇索引非聚簇索引:獨(dú)立于表的物理排序的索引,通過(guò)表中對(duì)應(yīng)行的邏輯指針來(lái)實(shí)現(xiàn)數(shù)據(jù)的快速訪問(wèn)
6.2.3 索引的優(yōu)缺點(diǎn)
缺點(diǎn)
占用存儲(chǔ)的空間:需要額外的空間來(lái)存儲(chǔ)索引,一旦包含多個(gè)索引時(shí)占有的空間會(huì)很多增加寫(xiě)操作的成本:索引的創(chuàng)建需要你手動(dòng)創(chuàng)建,當(dāng)然有些約束會(huì)自動(dòng)創(chuàng)建索引更新頻繁的表性能下降:對(duì)于經(jīng)常修改數(shù)據(jù)的表,索引的更新會(huì)影響表的性能索引選擇不當(dāng):過(guò)多或者不必要的索引會(huì)降低查詢的性能,增加了數(shù)據(jù)庫(kù)的管理和維護(hù)的成本索引的維護(hù):面對(duì)多個(gè)索引,維護(hù)起來(lái)需要消耗大量成本
6.2.4 索引的創(chuàng)建
create index 索引名 on 表名 (字段1,字段2....) create index sid_uq on sttu (sid); -- 定義主鍵約束或者唯一約束會(huì)自動(dòng)創(chuàng)建索引 create table idex_table ( did number(4), name varchar2(50), constraint index_uq unique (did), constraint index_prim primary key (name) );
6.3 創(chuàng)建索引的原則(重中之重)
1)最左前綴匹配原則,組合索引非常重要的原則,mysql會(huì)一直向右匹配直到遇到范圍查詢(>、
2)較頻繁作為查詢條件的字段才去創(chuàng)建索引
3)更新頻繁字段不適合創(chuàng)建索引
4)若是不能有效區(qū)分?jǐn)?shù)據(jù)的列不適合做索引列
5)盡量的擴(kuò)展索引,不要新建索引
6)定義有外鍵的數(shù)據(jù)列一定要建立索引。
7)對(duì)于那些查詢中很少涉及的列,重復(fù)值比較多的列不要建立索引。
8)對(duì)于定義為text、image和bit的數(shù)據(jù)類(lèi)型的列不要建立索引。
6.3.1 創(chuàng)建索引時(shí)需要注意什么
非空字段應(yīng)該指定列為NOT NULL,空值很難查詢,除非你想存儲(chǔ)NULL,所以應(yīng)該用0、一個(gè)特殊的值或者一個(gè)空串代替空值;取值離散大的字段(變量各個(gè)取值之間的差異程度)的列放到聯(lián)合索引的前面,可以通過(guò)count()函數(shù)查看字段的差異值,返回值越大說(shuō)明字段的唯一值越多字段的離散程度高;索引字段越小越好:數(shù)據(jù)庫(kù)的數(shù)據(jù)存儲(chǔ)以頁(yè)為單位一頁(yè)存儲(chǔ)的數(shù)據(jù)越多一次IO操作獲取的數(shù)據(jù)越大效率越高。
6.4 什么是序列?
是數(shù)據(jù)庫(kù)中用于生成唯一數(shù)值序列的對(duì)象。他是一個(gè)獨(dú)立的數(shù)據(jù)庫(kù)對(duì)象,序列生成的數(shù)值通常用于為表的主鍵提供唯一的標(biāo)識(shí)符,或者作用于其他唯一遞增數(shù)值的列。序列生成的值不依賴(lài)于表中的數(shù)據(jù),而是由數(shù)據(jù)庫(kù)自身維護(hù)和生成。
6.5 序列的操作
6.5.1 創(chuàng)建序列
-- 創(chuàng)建了一個(gè)序列,從 1 開(kāi)始每次遞增 1,nocache 參數(shù)表示不緩存序列的值,而是直接從數(shù)據(jù)庫(kù)中獲取
create sequence SequenceName
start with 1
increment by 1
nocache
-- 刪除序列
drop sequence SequenceName
6.5.2 舉例
-- 子查詢建表
create table testseq as select sid,sname,sage,ssex from student;
select * from testseq delete from testseq
-- 創(chuàng)建序列
create sequence test_sid;
-- 使用序列添加數(shù)據(jù)
insert into testseq(sid,sname,sage,ssex)
values(test_sid.nextval,'張三',20,'男');
insert into testseq(sid,sname,sage,ssex)
values(test_sid.nextval,'李四',19,'女');
insert into testseq(sid,sname,sage,ssex)
values(test_sid.nextval,'王五',21,'男');
6.5.3 自定義序列
-- 自定義序列
test_sid1 create sequence test_sid1
minvalue 10019 -- 定義最小值
start with 10019 -- 開(kāi)始值
maxvalue 99999 -- 序列最大值
increment by 1; -- 規(guī)定自增值
6.5.4 查看序列
-- 查看模當(dāng)前序列值
select test_sid1.currval from dual;
6.6 什么是PL/SQL?
集中處理一些可以復(fù)制、反復(fù)執(zhí)行的SQL操做
set serveroutput on
declare
聲明部分
begin
主體內(nèi)容
exception
捕獲異常
end;
6.6.1 基本輸出
begin
dbms_output.put_line('Hello World!');
end;
/
6.6.2 變量輸出
declare
i number;
-- 定義變量 i 是 number 類(lèi)型
begin
i := 30;
-- 給 i 賦值 dbms_output.put_line(i); -- 輸出 i
end;
6.7 PL/SQL異常
異常是執(zhí)行期間的錯(cuò)誤,PL/SQL支持程序員在程序中使用 EXPECTION 塊來(lái)捕獲此類(lèi)情況,并對(duì)錯(cuò)誤情況采取適當(dāng)?shù)拇胧?/p>
6.7.1 異常處理的語(yǔ)法
when 異常名 then 處理代碼塊
6.7.2 異常列表
1. ACCESS_INTO_NULL:訪問(wèn)未定義的對(duì)象。
2. CASE_NOT_FOUND:CASE語(yǔ)句中沒(méi)有匹配的WHEN條件,并且沒(méi)有設(shè)置ELSE。
3. COLLECTION_IS_NULL:集合元素未初始化。
4. CURSOR_ALREADY_OPEN:游標(biāo)已經(jīng)打開(kāi)。
5. DUP_VAL_ON_INDEX:唯一索引列上存在重復(fù)的值。
6. INVALID_CURSOR:對(duì)非法的游標(biāo)進(jìn)行操作。
7. INVALID_NUMBER:內(nèi)嵌的SQL語(yǔ)句無(wú)法將字符轉(zhuǎn)換為數(shù)字。
8. NO_DATA_FOUND:SELECT INTO語(yǔ)句未返回任何行,或者訪問(wèn)未初始化索引表的元素。
9. TOO_MANY_ROWS:執(zhí)行SELECT INTO語(yǔ)句時(shí),結(jié)果集超過(guò)一行。
10. ZERO_DIVIDE:除數(shù)為0。
11. SUBSCRIPT_BEYOND_COUNT:下標(biāo)超過(guò)嵌套表或VARRAY的最大值。
12. SUBSCRIPT_OUTSIDE_LIMIT:使用嵌套表或VARRAY時(shí),下標(biāo)指定為負(fù)數(shù)。
13. VALUE_ERROR:賦值時(shí),變量長(zhǎng)度不足以容納實(shí)際數(shù)據(jù)。
14. LOGIN_DENIED:當(dāng)PL/SQL應(yīng)用程序連接到Oracle數(shù)據(jù)庫(kù)時(shí),提供了不正確的用戶名或密碼。
15. NOT_LOGGED_ON:在沒(méi)有連接到Oracle數(shù)據(jù)庫(kù)的情況下嘗試訪問(wèn)數(shù)據(jù)。
16. PROGRAM_ERROR:PL/SQL內(nèi)部問(wèn)題,可能需要重新安裝數(shù)據(jù)字典和PL/SQL系統(tǒng)包。 17. ROWTYPE_MISMATCH:宿主游標(biāo)變量與PL/SQL游標(biāo)變量的返回類(lèi)型不兼容。
18. SELF_IS_NULL:在null對(duì)象上調(diào)用對(duì)象方法時(shí)使用了對(duì)象類(lèi)型。
19. STORAGE_ERROR:運(yùn)行PL/SQL時(shí),超出了內(nèi)存空間。
20. SYS_INVALID_ID:無(wú)效的ROWID字符串。
21. TIMEOUT_ON_RESOURCE:Oracle在等待資源時(shí)超時(shí)。
6.7.3 處理異常
-- 除數(shù)為 0 的異常
declare
i number;
begin
i:=1/0;
exception
when zero_divide then
dbms_output.put_line('不能除0');
end;
-- 唯一索引列上存在重復(fù)的值
declare
????????v_empno number := 7369; -- 定義變量 v_empno 并賦值
begin
???????? insert into emp (empno) values (v_empno); -- 插入重復(fù)值
exception
????????when DUP_VAL_ON_INDEX then
????????????????dbms_output.put_line('存在相同的編號(hào)!');
end; /
-- CASE語(yǔ)句中沒(méi)有匹配的WHEN條件,并且沒(méi)有設(shè)置ELSE。
declare
????????v_grade char(1) := 'D';
begin
????????case v_grade
????????????????when 'A' then
????????????????????????dbms_output.put_line('優(yōu)秀');
????????????????when 'B' then
????????????????????????dbms_output.put_line('良好');
????????????????end case;
????????????????exception
????????????????????????when CASE_NOT_FOUND then
????????????????????????????????dbms_output.put_line('沒(méi)有匹配項(xiàng)');
end;
/
6.7.4 用戶輸入
-- 讓用戶輸入 sid 查找學(xué)生
declare -- 定義變量
????????v_sid number;
????????v_sname varchar2(30);
begin
????????v_sid :=&請(qǐng)輸入sid; -- & 提示輸出,輸入的 sid 存入進(jìn) v_sid 內(nèi)
????????-- 把 v_sid 當(dāng)做條件放進(jìn)查詢語(yǔ)句中,where 實(shí)際上判斷的是輸入的 sid
????????-- 將找到的 sname 通過(guò) into 存入變量 v_sname 內(nèi)
????????select sname into v_sname from student where sid = v_sid;
????????-- 輸出變量 v_sname
????????dbms_output.put_line(v_sname);
exception
????????-- 捕獲異常
????????when NO_DATA_FOUND then
????????dbms_output.put_line('沒(méi)有該學(xué)生!');
end;
6.8 循環(huán)
6.8.1 loop循環(huán)
loop
循環(huán)語(yǔ)句;
exit when 終止的條件;
循環(huán)條件必須更改;
end loop;
-- 循環(huán)輸出 1 ~ 指定值,用戶數(shù)指定值
declare
????????v_end number;
????????v_start number;
begin
????????v_end :=&請(qǐng)輸入結(jié)束的數(shù)字;
????????v_start := 1;
loop
????????dbms_output.put_line(v_start);
????????v_start := v_start + 1;
????????exit when v_start > v_end;
end loop;
end;
6.8.2 while循環(huán)
while(循環(huán)條件) loop
循環(huán)語(yǔ)句;
循環(huán)條件的改變;
end loop;
-- 循環(huán)輸出 1 ~ 指定值,用戶數(shù)指定值
declare
????????v_end number;
????????v_start number;
begin
????????v_end :=&請(qǐng)輸入結(jié)束的數(shù)字; v_start := 1;
????????-- 判斷開(kāi)始的條件 輸入的數(shù)字 大于 開(kāi)始的數(shù)字 才開(kāi)始循環(huán),如果不滿足條件結(jié)束循環(huán) ?while(v_start <= v_end) loop
????????dbms_output.put_line(v_start);
????????v_start := v_start + 1;
end loop;
end;
6.8.3 for循環(huán)
for 變量名稱(chēng) in 變量的初始值..結(jié)束值 loop
循環(huán)語(yǔ)句;
end loop;
-- 循環(huán)輸出 1 ~ 指定值,用戶數(shù)指定值
declare
????????v_end number;
begin
????????v_end :=&請(qǐng)輸入結(jié)束的數(shù)字;
for v_start in 1..v_end loop
????????dbms_output.put_line(v_start);
end loop;
end;
6.8.4 分支語(yǔ)句
6.8.4.1 if語(yǔ)句
if 條件 then
滿足條件,執(zhí)行這里;
end if;
-- 判斷能否談對(duì)象
declare
????????age number;
????????begin age :=&請(qǐng)輸入年齡;
if age >= 15 then
????????dbms_output.put_line('可以談戀愛(ài)了');
end if;
end;
6.8.4.2 if...else
declare
????????age number;
begin
????????age :=&請(qǐng)輸入年齡;
????????if age >= 15 then
????????dbms_output.put_line('可以談戀愛(ài)了');
????????else
????????dbms_output.put_line('不可以談戀愛(ài)');
????????end if;
end;
6.8.4.3 if..elsif..else
declare
????????age number;
begin
????????age :=&請(qǐng)輸入年齡;
????????if age >= 15 then
????????dbms_output.put_line('可以談戀愛(ài)了');
????????elsif
????????age <= 6 then -- 不要忘了then
????????dbms_output.put_line('好好讀書(shū)!');
????????else
????????dbms_output.put_line('輸入范圍內(nèi)數(shù)字');
????????end if;
exception
????????when VALUE_ERROR then
????????dbms_output.put_line('數(shù)據(jù)不合法');
end;
6.8.4.4 goto 標(biāo)記點(diǎn)的用法
-- 打印偶數(shù)
declare
????????i number;
????????j number; begin i :=0;
-- 循環(huán)開(kāi)始的默認(rèn)值
loop
????????<
????????i := i+1; j :=&請(qǐng)輸入;
if mod(i,2)=1 then -- 通過(guò)求余函數(shù)判斷是奇數(shù)還是偶數(shù)
????????goto fo; -- 如果不是奇數(shù)就往下執(zhí)行,如果是奇數(shù)重來(lái)
????????end if;
????????exit
????????????????when i > j; -- 退出goto的條件
????????????????dbms_output.put_line(i);
????????????????end loop;
end;
7 函數(shù)、用戶命令、游標(biāo)、存儲(chǔ)過(guò)程
7.1 什么是函數(shù)
作為編程范式的一個(gè)組成部分,一段可重復(fù)使用的代碼塊,接收參數(shù),并返回一個(gè)具體的值
7.1.1 函數(shù)使用
函數(shù)定義
create [or replace] function 函數(shù)名 (參數(shù) 類(lèi)型1,參數(shù)2 類(lèi)型2,...)
return 返回值類(lèi)型
is/as
???????? [定義變量]
begin
????????代碼塊
????????return 結(jié)果;
exception
????????...
end;
函數(shù)的參數(shù)模式只能是 in 模式,可以省略 in函數(shù)聲明的時(shí)候,必須使用 return 加返回值類(lèi)型return 的返回值類(lèi)型只需要告訴類(lèi)型,不需要定義長(zhǎng)度 return varchar2 變量: 數(shù)據(jù)類(lèi)型 varchar2(30)函數(shù)的結(jié)果必須通過(guò) return 返回出去,函數(shù)要有返回值
舉例
-- 無(wú)參函數(shù)
create or replace function sayHello
return varchar2
????????is begin return 'Hello World!';
end; select sayHello() from dual;
-- 有參函數(shù)
create or replace function sayHy(sname in varchar2)
return varchar2
is
????????rec varchar2(50);
begin
????????if sname is null or sname = '' then
????????????????rec := 'Hello!';
????????else
????????????????rec := 'Hello,'||sname;
????????end if;
????????return rec;
end;
select sayHy('') from dual;
練習(xí)
-- 根據(jù)員工的編號(hào),計(jì)算員工的年收入(工資 + 獎(jiǎng)金)* 12
create or replace function calculateyearlyIncome(eno in emp.empno%type)
return number
is
????????v_sal emp.sal%type;
????????v_comm emp.comm%type;
begin
????????select sal,comm into v_sal,v_comm from emp where empno = eno;
????????if v_sal is null then
????????????????v_sal :=0;
????????end if;
????????if v_comm is null then
????????????????v_comm :=0;
????????end if;
????????return (v_sal + v_comm) * 12;
????????end;
select e.*,calculateyearlyIncome(e.empno) as 年收入 from emp e;
-- 傳入時(shí)間,返回入職時(shí)間比這個(gè)時(shí)間早的所有員工的平均工資
create or replace function calculateAvgSal(hdate in emp.hiredate%type)
return number
is
????????avg_sal number;
begin
????????select avg(sal) into avg_sal from emp where hiredate < hdate;
????????return avg_sal;
end;
select calculateAvgSal(TO_DATE('2000-01-01','YYYY-MM-DD')) as 平均工資 from dual;
7.2 查看所有用戶
select * from all_users;
7.2.1 創(chuàng)建用戶
需要管理員用戶完成,Oracle用戶分為三種身份
normal:普通用戶sysoper:數(shù)據(jù)庫(kù)操作員,可以打開(kāi)關(guān)閉數(shù)據(jù)庫(kù)服務(wù)器、備份數(shù)據(jù)庫(kù)、恢復(fù)數(shù)據(jù)、日志歸檔...sysdba:數(shù)據(jù)庫(kù)管理員,管理數(shù)據(jù)庫(kù)、管理用戶
create user 用戶名 identified by "密碼";
7.2.2 刪除用戶
drop user 用戶名 cascade;
7.2.3 解鎖用戶
unlock:解鎖
lock:鎖定
alter user 用戶名 account unlock;
7.2.4 修改密碼
alter user 用戶名 identified by "密碼";
7.2.5 權(quán)限
數(shù)據(jù)庫(kù)管理權(quán)限
create session:登錄權(quán)限
create table:創(chuàng)建表的權(quán)限
create index:創(chuàng)建索引的權(quán)限
create view:創(chuàng)建視圖的權(quán)限
create sequence:創(chuàng)建序列的權(quán)限
7.2.6 數(shù)據(jù)操作權(quán)限
insert:插入數(shù)據(jù)的權(quán)限
delete:刪除數(shù)據(jù)的權(quán)限
update:修改數(shù)據(jù)的權(quán)限
select:查詢數(shù)據(jù)的權(quán)限
舉例
-- 賦予權(quán)限
grant 權(quán)限名 to 用戶名;
-- 收回權(quán)限
revoke 權(quán)限名 from 用戶名;
7.2.7 角色
把很多權(quán)限組合成一個(gè)角色,然后將該角色賦給某個(gè)用戶,那么這個(gè)用戶就會(huì)擁有這個(gè)角色的權(quán)限
-- 授權(quán)
grant 權(quán)限名 on 表名 to 用戶1,用戶2....;
--
grant select,insert,update on CCOL$ to jack,yxy;
-- 收回權(quán)限
revoke 權(quán)限名 on 表名 from 用戶1,用戶2....;
有一些內(nèi)置的角色,connect、dba可以將權(quán)限賦給用戶
grant 內(nèi)置角色名 to 用戶名;
7.3 什么是游標(biāo)
游標(biāo)是SQL的內(nèi)存工作區(qū),由系統(tǒng)或用戶以變量的形式進(jìn)行定義
作用
用于臨時(shí)存儲(chǔ)從數(shù)據(jù)庫(kù)中提取的數(shù)據(jù)塊
7.3.1 分類(lèi)
顯示游標(biāo)、隱式游標(biāo)
舉例
select into 一次只能從數(shù)據(jù)庫(kù) 提取一行數(shù)據(jù)
declare
????????v_ename varchar2(50);
????????v_deptno number(10);
begin
????????v_deptno :=&plaseput;
????????select into v_ename from emp where deptno = v_deptno;
????????dbms_output.put_line(v_ename);
end;
/
7.3.1.1 隱式游標(biāo)
以下內(nèi)容會(huì)觸發(fā)隱式游標(biāo)
-- 插入數(shù)據(jù)
insert into testseq(sid,sname,sage,ssex)
???????? values(test_sid.nextval,'王五',21,'男');
-- 更新數(shù)據(jù)
update testseq set sname = '王wu' where sname = '王五'
-- 刪除數(shù)據(jù)
delete from testseq where sname = '王wu'
-- into 單行查詢
declare
????????v_ename varchar2(50);
????????v_empno number(10);
begin
????????v_empno :=&plaseput;
????????select ename into v_ename from emp where empno = v_empno; ????????dbms_output.put_line(v_ename);
end;
/
屬性
屬性 返回值類(lèi)型 含義 sql%rowcount 整形 代表DML語(yǔ)句成功執(zhí)行的數(shù)據(jù)行數(shù) sql%found 布爾型 值為true表是插入、刪除、更新、單行查詢等成功 sql%notfound 布爾型 值為true表是插入、刪除、更新、單行查詢等未找到所匹配的行 sdql%isopen 布爾型 在DML語(yǔ)句執(zhí)行過(guò)程為真執(zhí)行結(jié)束為假
用于判斷DML語(yǔ)句的執(zhí)行結(jié)果以及控制程序的流程
舉例
sql%rowcount 獲取 插入、更新、刪除操作影響的行數(shù)
-- 刪除 student 表中年齡大于等于 20 的人
-- 設(shè)置回滾點(diǎn)
savepoint a;
declare
????????row_count number;
begin
????????delete from student where sage >= 20;
????????-- 設(shè)置隱式游標(biāo)
????????row_count := sql%rowcount;
????????dbms_output.put_line('刪除成功'||row_count||'行數(shù)!');
end;
-- 回滾
rollback to a;
sql%found 判斷 DML 操作是否成功
-- 查詢 1005 號(hào)學(xué)生的姓名,判斷是否查詢成功
declare
????????s_sname varchar2(50);
begin
????????select sname into s_sname from student where sid = 10005;
????????if sql%found then
????????dbms_output.put_line('找到了:'||s_sname||'!');
????????else
????????????????dbms_output.put_line('沒(méi)找到!');
????????end if;
end;
/
sql%notfound 判斷 DML 操作是否找到任何一個(gè)匹配的行
-- 查詢 10018 號(hào)學(xué)生的姓名,判斷是否查詢成功
declare
????????s_sname varchar2(50);
begin
????????select sname into s_sname from student where sid = 10005;
????????if sql%notfound then
????????dbms_output.put_line('沒(méi)找到!');
????????else
????????dbms_output.put_line('找到了:'||s_sname||'!');
????????end if;
end;
/
-- 異常
declare
????????s_sname varchar2(50);
begin
????????select sname into s_sname from student where sid = 10019;
????????dbms_output.put_line('找到了:'||s_sname||'!');
exception
????????when no_data_found then
????????????????dbms_output.put_line('沒(méi)找到!');
end;
/
sdql%isopen 檢查隱式游標(biāo)在 DML 操作時(shí)的狀態(tài)
-- 假設(shè)游標(biāo) c_student 查詢了學(xué)生的姓名
-- fetch 語(yǔ)句 into 子句 與查詢的列數(shù)量匹配
-- 將結(jié)果賦值給變量 s_sname ,并輸出學(xué)生的姓名
-- 不使用 sql%isopen 來(lái)判斷游標(biāo)是否處于打開(kāi)狀態(tài)
-- 而是直接進(jìn)入循環(huán)并使用 c_student%notfound 作為循環(huán)退出的條件
-- 使用顯示游標(biāo)
declare
????????cursor c_student is
????????????????select sname from student;
????????s_sname varchar2(50);
begin
????????open c_student;
????????loop
????????????????fetch c_student into s_sname;
????????????????-- 當(dāng)沒(méi)有值可以獲取的時(shí)候退出循環(huán)
????????????????exit when c_student%notfound;
????????????????dbms_output.put_line('學(xué)生姓名:'||s_sname);
????????????????end loop;
????????????????dbms_output.put_line('未找到');
????????????????close c_student;
end;
/
-- 使用隱式游標(biāo)
declare
????????cursor c_student is
????????????????select sname from student;
????????s_sname varchar2(50);
begin
????????open c_student;
????????loop
????????????????fetch c_student into s_sname;
????????????????-- 當(dāng)沒(méi)有值可以獲取的時(shí)候退出循環(huán)
????????????????exit when c_student%notfound;
????????????????dbms_output.put_line('學(xué)生姓名:'||s_sname);
????????????????end loop;
????????????????dbms_output.put_line('游標(biāo)已關(guān)閉');
????????????????if c_student%isopen then
????????????????close c_student;
????????????????end if;
end;
/
7.3.1.2顯示游標(biāo)
需要我們自己手動(dòng)聲明、打開(kāi)、提取數(shù)據(jù)、關(guān)閉
-- 聲明游標(biāo)
cursor 游標(biāo)名 is select ...
-- 打開(kāi)游標(biāo)
open 游標(biāo)名
-- 提取數(shù)據(jù)
fetch 游標(biāo)名 into [v1,v2....]
fetch 游標(biāo)名 into v1
-- 關(guān)閉游標(biāo)
close 游標(biāo)名
-- 提取 SMITH 的數(shù)據(jù)
-- 提取 student 表中的 10001 的姓名和籍貫
declare
????????v_sname varchar2(10);
????????v_snativeplace varchar(10);
????????-- 聲明游標(biāo)
????????cursor stu_var is
????????????????select sname,snativeplace from student;
begin
????????-- 打開(kāi)游標(biāo)
????????open stu_var;
????????-- 提取數(shù)據(jù)
????????fetch stu_var into v_sname,v_snativeplace;
????????dbms_output.put_line(v_sname||','||v_snativeplace);
????????close stu_var;
end;
/
7.3.2 for循環(huán)游標(biāo)
-- 輸出 empno、job、ename
declare
????????cursor e_emp is
????????????????select * from emp;
????????????????-- 聲明和emp表中字段、類(lèi)型相同的變連
????????????????empInfo emp%rowtype;
????????????????cou number;
begin
????????-- 循環(huán)游標(biāo)e_emp,把值給empInfo
????????????????for empInfo in e_emp loop
????????-- 值在傳給cou
????????cou := e_emp%rowcount;
????????dbms_output.put_line(cou||'雇員編號(hào):'||empInfo.empno||',雇員工作:'||empInfo.job||',雇員名字:'||empInfo.ename);
????????end loop;
end;
7.3.3 while循環(huán)游標(biāo)
-- 輸出 empno、ename
declare
????????cursor mycur is select * from emp;
????????empInfo emp%rowtype;
begin
????????open mycur;
????????-- 使游標(biāo)指向下一行
????????fetch mycur into empInfo;
????????-- 判斷游標(biāo)的這一行是否有數(shù)據(jù)
????????while(mycur%found) loop
????????dbms_output.put_line('雇員編號(hào):'||empInfo.empno||',雇員名字:'||empInfo.ename); fetch mycur into empInfo;
????????end loop;
end;
7.3.4 loop循環(huán)游標(biāo)
-- 輸出 empno、ename
declare
????????cursor mycur is select * from emp;
????????empInfo emp%rowtype;
begin
????????open mycur;
????????loop
????????fetch mycur into empInfo;
????????exit when mycur%notfound;
????????dbms_output.put_line('雇員編號(hào):'||empInfo.empno||',雇員名字:'||empInfo.ename);
????????end loop;
end;
練習(xí)
-- 一次性上漲全部人的工資。根據(jù)他所在的部門(mén)上漲工資
-- 10 :上漲 10%
-- 20 :上漲 20%
-- 30 :上漲 30%
-- 雖然上漲工資,但是最高不能超過(guò) 5000,如果工資超過(guò) 5000 那么工資就是5000
-- 通過(guò)查詢判斷是否成功 select * from emp;
declare
????????cursor c_emp is select empno,sal,deptno from emp;
????????v_empno emp.empno%type;
????????v_deptno emp.deptno%type;
????????v_sal emp.sal%type;
begin
????????for rec in c_emp loop
????????????????v_empno := rec.empno;
????????????????v_deptno := rec.deptno;
????????????????v_sal := rec.sal;
?????????????????-- 調(diào)整工資
????????????????CASE v_deptno
????????????????when 10 then
????????????????????????v_sal := least(v_sal + (v_sal * 0.1),5000);
????????????????when 20 then
????????????????????????v_sal := least(v_sal + (v_sal * 0.2),5000);
????????????????when 30 then
????????????????????????v_sal := least(v_sal + (v_sal * 0.3),5000);
????????????????else v_sal := v_sal * 1;
????????????????end case;
????????????????update emp set sal = v_sal where empno = v_empno;
????????????????end loop;
????????????????commit;
end;
7.4 什么是存儲(chǔ)過(guò)程
封裝了一段或者多段sql語(yǔ)句的pl/sql代碼塊
存儲(chǔ)過(guò)程的優(yōu)點(diǎn)
簡(jiǎn)化復(fù)雜操作:將很多條的sql語(yǔ)句封裝為一個(gè)獨(dú)立的單元,使用時(shí)只需要去調(diào)用該單元即可增加數(shù)據(jù)的獨(dú)立性:將數(shù)據(jù)庫(kù)基礎(chǔ)數(shù)據(jù)和程序隔離開(kāi),基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)變化時(shí),只需要存儲(chǔ)過(guò)程不需要修改原代碼提高安全性:減少了執(zhí)行多條sql語(yǔ)句報(bào)錯(cuò)提高性能:只需要編譯一次即可運(yùn)行多條sql語(yǔ)句
存儲(chǔ)過(guò)程的參數(shù)
in:定義輸入?yún)?shù),用于傳遞參數(shù)給存儲(chǔ)過(guò)程out:定義輸出參數(shù),用于從存儲(chǔ)過(guò)程獲取參數(shù)in out:定義輸入輸出參數(shù)
?7.4.1?沒(méi)有參數(shù)的存儲(chǔ)過(guò)程
-- 給指定的編號(hào)年齡添加2歲
-- stu_pro 是存儲(chǔ)過(guò)程名
create or replace procedure stu_pro
is
begin
????????update student set sage = sage + 2 where sid = 10001;
????????commit;
????????dbms_output.put_line('修改成功!');
end;
-- 調(diào)用存儲(chǔ)過(guò)程
begin
stu_pro;
end;
-- 查詢結(jié)果
select * from student;
7.4.2 有參數(shù)的存儲(chǔ)過(guò)程
-- 指定人添加指定年齡 -- 定義存儲(chǔ)過(guò)程并且傳入兩個(gè)參數(shù) var_1 和 var_2
create or replace procedure pro_stu(var_1 in varchar2,var_2 in number)
is
begin
update student set sage = sage + var_2 where sname = var_1;
commit;
dbms_output.put_line(var_1||'年齡增加了'||var_2||'歲!');
end;
declare
begin
????????pro_stu('李四',2);
end;
7.4.3 out 和 in out參數(shù)的存儲(chǔ)過(guò)程
create or replace procedure pro_out
(var_1 in out number,var_2 out student.sname%type,var_3 out student.sage%type)
is
begin
????????select sname,sage into var_2,var_3 from student where sid = var_1;
????????end;
declare
????????ex_var_1 number;
????????ex_var_2 student.sname%type;
????????ex_var_3 student.sage%type;
begin
????????ex_var_1 :=&請(qǐng)輸入sid;
????????pro_out(ex_var_1,ex_var_2,ex_var_3);
????????dbms_output.put_line('學(xué)號(hào)為:'||ex_var_1||',姓名是:'||ex_var_2||',年齡是:'||ex_var_3);
end;
7.4.4 刪除存儲(chǔ)過(guò)程
drop procedure 存儲(chǔ)過(guò)程名
函數(shù)和存儲(chǔ)過(guò)程的區(qū)別
函數(shù)主要用于返回計(jì)算結(jié)果,存儲(chǔ)過(guò)程執(zhí)行sql語(yǔ)句關(guān)鍵字不一樣,函數(shù)function,存儲(chǔ)過(guò)程是procedure存儲(chǔ)過(guò)程可以由輸入輸出的參數(shù),函數(shù)只有輸入的參數(shù)函數(shù)有返回值,存儲(chǔ)過(guò)程沒(méi)有存儲(chǔ)過(guò)程調(diào)用在plsql的代碼塊里,只能在sql語(yǔ)句
8 數(shù)據(jù)字典、數(shù)據(jù)庫(kù)設(shè)計(jì)、觸發(fā)器、in和existi
8.1 什么是數(shù)據(jù)字典?
提供了對(duì)數(shù)據(jù)結(jié)構(gòu)和對(duì)象元數(shù)據(jù)信息的查詢和訪問(wèn),幫助你了解和管理數(shù)據(jù)庫(kù)的各個(gè)方面
舉例
-- 查詢 scott 用戶下所有表
select TABLE_NAME from all_tables where owner = 'SCOTT';
-- 查詢 emp 表中所有的字段
select * from all_tab_columns where TABLE_NAME = 'EMP';
-- 列出 emp 表的 索引列
select * from all_ind_columns where TABLE_NAME = 'EMP'
-- 列出 emp 表的 約束
select * from all_constraints where TABLE_NAME = 'EMP'
8.2 什么是數(shù)據(jù)庫(kù)三大范式?
第一范式:屬性不可再分
第二范式:在第一范式的基礎(chǔ)上,屬性完全依賴(lài)于主鍵
第三范式:在第二范式的基礎(chǔ)上,屬性不依賴(lài)于其他非主鍵屬性
舉例
第一范式
以上內(nèi)容就不符合,聯(lián)系方式字段還可以再分
修改
第二范式
互相之間都可以作為主鍵并且互相依賴(lài),這是違背第二范式
修改
保證每張表只有一個(gè)主鍵依賴(lài)
?
第三范式
其他的屬性不可以當(dāng)主鍵,只有一個(gè)屬性可以當(dāng)作主鍵
舉例
-- 建表 -- 建一個(gè)訂單表,含有訂單內(nèi)容的信息
?CREATE TABLE orders1(
????????order_id NUMBER PRIMARY KEY,
????????customer_id NUMBER,
????????order_date DATE,
????????total_amount NUMBER,
????????CONSTRAINT fk_orders_customer
????????FOREIGN KEY(customer_id)
????????REFERENCES customers1(customer_id)
);
-- 建一個(gè)客戶表,含有客戶信息
CREATE TABLE customers1(
????????customer_id NUMBER PRIMARY KEY,
????????customer_name VARCHAR2(100),
????????customer_email VARCHAR2(100),
????????customer_phone VARCHAR2(100)
);
修改
查看是否存在能夠單獨(dú)當(dāng)主鍵的列或者會(huì)造成多個(gè)數(shù)據(jù)冗雜的列,需要單獨(dú)拎出來(lái)建表
-- 建一個(gè)訂單表,含有訂單內(nèi)容的信息
CREATE TABLE orders1(
????????order_id NUMBER PRIMARY KEY,
????????customer_id NUMBER,
????????order_date DATE,
????????CONSTRAINT fk_orders_customer
????????FOREIGN KEY(customer_id)
????????REFERENCES customers1(customer_id)
);
-- 建一個(gè)客戶表,含有客戶信息
CREATE TABLE customers1(
????????customer_id NUMBER PRIMARY KEY,
????????customer_name VARCHAR2(100)
);
-- detail
CREATE TABLE detail1(
????????order_id NUMBER,
????????item_id NUMBER,
????????item_quantity NUMBER,
????????item_price NUMBER,
????????CONSTRAINT pk_order_detail
????????PRIMARY KEY (order_id,item_id),
????????CONSTRAINT fk_order_detail
????????FOREIGN KEY(order_id)
????????REFERENCES order1(order_id),
????????CONSTRAINT fk_order_detail
????????FOREIGN KEY(item_id)
????????REFERENCES item1(item_id)
);
-- item
CREATE TABLE item1(
????????item_id NUMBER PRIMARY KEY,
????????item_name VARCHAR2(100),
????????item_description VARCHAR2(100),
????????item_price NUMBER
);
8.3 什么是觸發(fā)器?
本身是一種數(shù)據(jù)庫(kù)的對(duì)象,用于在指定的事件發(fā)生的時(shí)候會(huì)自動(dòng)執(zhí)行一段plsql代碼
功能
允許/限制對(duì)表的修改自動(dòng)生成派生列,自增字段強(qiáng)制保證數(shù)據(jù)的統(tǒng)一性提供審計(jì)和日志記錄防止無(wú)效的事務(wù)處理,為了避免鎖的發(fā)生啟用復(fù)雜的業(yè)務(wù)邏輯
語(yǔ)法
create or replace trigger 觸發(fā)器名
{before | after} {insert | update | delete} o
n 表名
[for each row]
begin
????????plsql代碼
end;
觸發(fā)時(shí)間:{before | after}
指明觸發(fā)器何時(shí)執(zhí)行
before:在數(shù)據(jù)庫(kù)操作之前
after:在數(shù)據(jù)庫(kù)操作之后
觸發(fā)事件:{insert | update | delete}
指明哪些數(shù)據(jù)庫(kù)的操作會(huì)觸發(fā)此觸發(fā)器
for each row:表示觸發(fā)器為每一行數(shù)據(jù)執(zhí)行一次,如果省略此選項(xiàng)觸發(fā)器只會(huì)執(zhí)行一次
舉例
-- 更新學(xué)生表之前觸發(fā),限制不允許在周末修改表
create or replace trigger auth_stu
before insert or update or delete
on student
begin
-- 這里添加的是判斷條件
????????if (to_char(sysdate,'DY') = '星期二') then
????????????????raise_application_error(-20600,'不能修改');
????????????????end if;
????????end;
-- 在下午兩點(diǎn)前不允許插入數(shù)據(jù)
create or replace trigger time_stu
????????before insert on test_log
????????for each row
declare
????????current_time timestamp;
begin
????????current_time := systimestamp;
????????if current_time < timestamp '2023-08-01 14:00:00' then
????????????????raise_application_error(-20001,'不能插入');
????????end if;
end;
我們對(duì) test1 執(zhí)行操作,將記錄保存在 test_long內(nèi)
create table test1(
????????t_id number(4),
????????t_name varchar2(20),
????????t_age number(2),
????????t_sex char
);
create table test_log(
????????l_user varchar2(15),
????????l_type varchar2(15),
????????l_date varchar2(30)
);
-- 對(duì)test1 進(jìn)行操作,將操作日志保存在 test_log 內(nèi)
create or replace trigger test1_log
????????after delete or insert or update on test1
declare
????????v_type varchar2(15);
begin
????????if inserting then
????????????????v_type := 'insert';
????????????????dbms_output.put_line('已記錄');
????????elsif updating then
????????????????v_type := 'update';
????????????????dbms_output.put_line('已記錄');
????????elsif deleting then
????????????????v_type := 'delete';
????????????????dbms_output.put_line('已記錄');
????????end if;
insert into test_log
????????values(user,v_type,to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'));
end;
select * from test1
select * from test_log
insert into test1 values(103,'楊芯葉',19,'男');
update test1 set t_age = 20 where t_age = 19;
delete test1 where t_id = 103
8.3 exists
邏輯計(jì)算符,exists 用于判斷子查詢返回的結(jié)果是否為空,如果不為空 exists 成立,主sql語(yǔ)句會(huì)執(zhí)行,反之不執(zhí)行
舉例
-- 如果部門(mén)名稱(chēng)中含有字母A,則查詢所有員工的信息
select * from emp where exists (
select * from dept where ename like '%A%' and deptno = emp.deptno)
not exists
-- 如果平均工資不小于 1500 的部門(mén)信息,則查詢所有部門(mén)信息(not exists)
select * from dept
where not exists (
select deptno from emp
where deptno = dept.deptno
group by deptno
having avg(sal) < 1500)
8.5 In
邏輯運(yùn)算符,用于判斷一個(gè)值是否存在與子查詢的結(jié)果集中,如果存在條件成立,主SQL語(yǔ)句執(zhí)行
如何選擇in和existi
假設(shè)B表做子查詢
A表有10000條記錄,B表有1000000條記錄,那么會(huì)遍歷10000 * 1000000次,效率很差,existsA表有10000條記錄,B表有100條,in比較快
結(jié)論
如果 子表 比 父表的數(shù)據(jù)多,用 exists,反之用 in此時(shí)主查詢有索引,in比較快not in 和 not exists,not exists 最快
練習(xí)
-- 返回?zé)o論是經(jīng)理還是非經(jīng)理,都沒(méi)有下屬的員工信息(not in)
select * from emp e
where e.empno not in (
select distinct(mgr) from emp)
-- 返回至少在一個(gè)職位上有員工的部門(mén)名稱(chēng)和地點(diǎn)
select d.dname,d.loc from dept d
where exists (
select 1 from emp e where e.deptno = d.deptno)
柚子快報(bào)激活碼778899分享:數(shù)據(jù)庫(kù)基礎(chǔ)教程(Oracle)
參考閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。