Oracle第二天
Oracle第二天
?
整體安排(3天)
第一天:Oracle的安裝配置(服務端和客戶端),SQL增強(單表查詢)。
第二天:SQL增強(多表查詢、子查詢、偽列-分頁),數據庫對象(表、約束、序列),Oracle基本體系結構、表空間、用戶和權限 ,視圖、同義詞
第三天:數據庫對象(索引、數據字典),PLSQL編程、存儲過程,數據庫備份和還原。
?
?
今天的安排:
?
?
?
多表(關聯)查詢
多表查詢也稱之為關聯查詢、多表關聯查詢等,主要是指通過多個表的關聯來獲取數據的一種方式。
多表映射關系
一對多:A表的一行數據,對應B表中的多條。如:一個部門可以對應多個員工.
多對一:B表中的多條對應A表的一行數據.如:多個員工對應一個部門.
多對多:學生和選修課表----學生和課程對應表。
一對一:人員基本信息和人員信息擴展表。
笛卡爾集
?
笛卡爾集對于我們數據庫的數據查詢結果的影響:
因此,在實際運行環境下,應避免使用全笛卡爾集。
?
笛卡爾集產生的條件:
- 省略連接條件
- 連接條件無效
如下示例:
如何避免笛卡爾集:
在 WHERE 加入有效的連接條件。
這時候就需要學習表關聯的幾種方式了。
多表連接的類型
根據連接方式的不同,Oracle的多表關聯的類型分為:
內連接、外連接、自連接。
內連接分為:等值內連接、不等值內連接
外連接分為:左外連接、右外連接、全外連接
自連接是一種特殊的關聯,可以包含內連接和外連接的連接方式。
關于sql99-了解
Oracle是關系型數據庫,它遵的規范(sql規范)。
但是,mysql和Oracle有些地方不一樣,原因:各個廠商的實現可能會有差別。
?
Sql99 是為了 統一規范多個關系型數據庫的通用語法的
?
多表連接的基本語法
Sql99的語法:
Oracle的語法:
?
sql語句 優化:
加上前綴:效率高!
?
內連接
等值內連接
等值內連接也稱之為等值連接。
【示例】
-需求:查詢一下員工信息,并且顯示其部門名稱
| --需求:查詢一下員工信息,并且顯示其部門名稱 SELECT * FROM emp t1,dept t2 WHERE t1.deptno=t2.deptno;--等值內連接,數據庫的私有擴展語法:隱式內連接(mysql,oracle都支持) SELECT * FROM emp t1 INNER JOIN dept t2 ON t1.deptno=t2.deptno;--sql99語法,顯示內連接(所有符合sql99規范的都支持) |
不等值內連接
不等值內連接也稱之為不等值連接。
【示例】需求:查詢員工信息,要求顯示員工的編號、姓名、月薪、工資級別。
| --分析:要完成這個需求,需要使用到下面兩張表: --需求:查詢員工信息,要求顯示員工的編號、姓名、月薪、工資級別。 SELECT * FROM emp t1,salgrade t2 WHERE t1.sal >=t2.losal AND t1.sal<=t2.hisal;--隱式語法 SELECT * FROM emp INNER JOIN salgrade ON emp.sal >=salgrade.losal AND emp.sal <=salgrade.hisal --sql99 |
?
表的別名
為什么要使用表的別名?
- 使用別名可以簡化查詢。
- 使用表名前綴可以提高執行效率。--SQL性能優化方案
- 在不同表中具有相同列名的列,可以用表的別名作為前綴來加以區分。
?
需要注意的是,如果一旦使用了表的別名,則不能再使用表的真名。
更多表的連接
注意:這個理論。
?
外連接
分為左外連接,右外連接,全外連接(oracle特有 mysql
沒有)。
?
左外連接
--查詢"所有"員工信息,要求顯示員工號,姓名 ,和部門名稱--要求使用左外連接
?
| --查詢"所有"員工信息,要求顯示員工號,姓名 ,和部門名稱--要求使用左外連接 SELECT * FROM emp t1 LEFT OUTER JOIN dept t2 ON t1.deptno=t2.deptno;--sql99標準語法 SELECT * FROM emp t1,dept t2 WHERE t1.deptno=t2.deptno(+);--oracle私有語法(mysql不支持),+放到右邊是左外,你可以認為(+)是附加補充的意思。--要求查詢所有的信息的表,我們可以稱之為主表,而補充信息的表,稱之為從表 |
?
右外連接
----查詢所有部門及其下屬的員工的信息。--右外連接
?
| SELECT * FROM emp t1 RIGHT OUTER JOIN dept t2 ON t1.deptno=t2.deptno;--sql99--右外連接--右邊表(dept)數據全部顯示。 SELECT * FROM emp t1,dept t2 WHEREt1.deptno(+)=t2.deptno;--oracle語法,右外連接 |
?
如何選擇左外和右外
| SELECT t1.*,t2.* FROM dept t1 ,emp t2 WHERE t1.deptno=t2.deptno(+); --1.到底是使用左外還是右外,主要是看兩張表的在語句中的位置, --兩張表是有主從關系,一般把主表放在左邊,----一般兩張表的情況下,我們都使用左連接. --2.+到底是放在條件哪邊?左外連接的+放在右邊,右外連接的+放在左邊.----記憶的方法:(+)放在從表的一方,起到數據附加的作用. 簡單的說:左外連接就是左邊的表的數據全部顯示,右外就是右邊的表的數據全部顯示。 |
?
這種(+)的寫法,只能用在Oracle。不能用于mysql!
?
一定要有主表和從表這個概念,分清那張是主表,哪張是從表。
把你想查詢基礎表當成左表。想把誰全部都查詢出來就當成主表。
到底哪張是主表哪張是從表?最終還看你的需求。
一般我們把主表放在左邊,使用左外連接。
一般情況下,我們就用左連接就行了。
?
全外連接
左表和右表的數據全部都顯示,而且不是笛卡爾集。
相當于左外+右外的數據。
【示例】
需求:要求將所有員工和所有部門都顯示出來
| --全外連接 SELECT * FROM emp t1 LEFT OUTER JOIN dept t2 on t1.deptno=t2.deptno UNION SELECT * FROM emp t1 RIGHT JOIN dept t2 ON t1.deptno=t2.deptno; SELECT * FROM emp t1 FULL OUTER JOIN dept t2 ON t1.deptno=t2.deptno;--sql99語法,Oracle沒有私有擴展的語法。而且,mysql沒有全外 |
?
?
自連接
自連接,就是將一張表當成兩張表來查詢。
示例
自連接的查詢的原理:就是將一張表當成兩張表來使用.
【示例】
1.查詢員工信息,要求同時顯示員工和員工的領導的姓名
2.查詢"所有"員工信息,要求同時顯示員工和員工的領導的姓名
| --查詢員工信息,要求同時顯示員工和員工的領導的姓名 SELECT * FROM emp t1,emp t2 WHERE t1.mgr=t2.empno; --查詢"所有"員工信息,要求同時顯示員工和員工的領導的姓名 SELECT * FROM emp t1,emp t2 WHERE t1.mgr=t2.empno(+); |
自連接是一種特殊的多表連接方式,其實含有內連接和外連接的操作.
注意問題:你也要注意笛卡爾集的產生.
?
子查詢
子查詢也稱之為嵌套子句查詢。
語法
語法上的運行使用規則:
- 子查詢 (內查詢、嵌套子句) 在主查詢之前一次執行完成。(子查詢先執行)
- 子查詢的結果被主查詢使用 (外查詢)。
- 子查詢要包含在括號內。
- 將子查詢放在比較條件的右側。
為什么要使用子查詢?
【需求】誰的工資比scott高?
采用連接的方式寫(這里是自連接,見下圖):
?
| --【需求】誰的工資比scott高? --多表關聯查詢:自連接的不等值連接 SELECT * FROM emp t1,emp t2 WHERE t2.ename='SCOTT' AND t1.sal>t2.sal --不等值連接 |
?
采用子查詢的方式寫:
| --子查詢 --分析一下:誰的工資比scott高?--->1,scott工資是多少2,誰的工資比3000高 SELECT sal FROM emp WHERE ename='SCOTT'; SELECT * FROM emp WHERE sal >3000; SELECT * FROM emp WHERE sal >(SELECT sal FROM emp WHERE ename='SCOTT'); |
?
對比可以發現:在某些業務上,子查詢比連接查詢更容易理解。
?
子查詢的分類
單行操作符(> = <)對應單行子查詢,多行操作符(in,not in)對應多行子查詢。
單行子查詢
語法要求:
- 只返回一行。
- 使用單行比較操作符。
?
其中<>也可以可以用!=代替,意思一樣。
【示例】--查詢部門名稱是SALES的員工信息
?
| --查詢部門名稱是SALES的員工信息 SELECT * FROM emp WHERE deptno=(SELECT deptno FROM DEPT WHERE dname ='SALES') |
了解:子查詢可以是一張表的數據,也可以是不同表的數據。
空值問題
【代碼】
需求:查找工作和'Rose' 這個人的工作一樣的員工信息
需求:查找工作和'Rose' 這個人的工作不一樣的員工信息
| --需求:查找工作和'Rose' 這個人的工作一樣的員工信息 SELECT job FROM emp WHERE ename = 'Rose'; ? SELECT * FROM emp WHERE job =(SELECT job FROM emp WHERE ename = 'Rose'); ? SELECT * FROM emp; ? --需求:查找工作和'Rose' 這個人的工作不一樣的員工信息 SELECT * FROM emp WHERE job !=(SELECT job FROM emp WHERE ename = 'Rose'); ? --結論: 只要子查詢返回的結果是null的話, 那么主查詢的結果就一定是null |
注意:使用子查詢的時候,一定要保證子查詢不能為空,否則數據就會出現異常。
非法使用單行子查詢
【示例】需求:查找工作和'SMITH' 'ALLEN'這兩個人的工作一樣的員工信息
多行子查詢
語法要求:
- 返回多行。
- 使用多行比較操作符。
In操作符
【示例】
需求:查找工作和'SMITH' 'ALLEN'這兩個人的工作一樣的員工信息
--需求:查找工作和'SMITH' 'ALLEN' 這兩個人的工作不一樣的員工信息
| --需求:查找工作和'SMITH' 'ALLEN' 這兩個人的工作一樣的員工信息 ? SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN'); SELECT * FROM emp WHERE job IN(SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN')); ? --需求:查找工作和'SMITH' 'ALLEN' 這兩個人的工作不一樣的員工信息 SELECT * FROM emp WHERE job NOT IN(SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN')); |
?
Any和all操作符
【示例】需求:查詢工資比30號部門任意一個員工的工資高的員工信息。--面試題
【示例】需求:查詢工資比30號部門所有員工的工資高的員工信息。
| --需求:查詢工資比30號部門任意一個員工的工資高的員工信息。--面試題 SELECT * FROM emp WHERE deptno =30; --任意一個:比最低的那個高就ok。 SELECT * FROM emp WHERE sal >(SELECT MIN(sal) FROM emp WHERE deptno=30); --any(多行函數) SELECT * FROM emp WHERE sal >ANY(SELECT sal FROM emp WHERE deptno=30); --【示例】需求:查詢工資比30號部門所有員工的工資高的員工信息。 SELECT * FROM emp WHERE sal>(SELECT MAX (sal) FROM emp WHERE deptno=30); --all(多個返回記錄)--max(sal) SELECT * FROM emp WHERE sal>ALL(SELECT sal FROM emp WHERE deptno=30); |
?
分析結果:
?
子查詢注意事項
|
?
虛擬臨時表是臨時表的一種,是運行過程中,內存中虛擬出來的一張臨時表,用于sql的操作。
【示例】
| --虛擬表 SELECT * FROM ( SELECT * FROM emp WHERE deptno=30 --虛表:將查詢結果再作為一張表來使用。 ) t WHERE sal>2000 |
?
子查詢和多表關聯查詢的選擇
理論上,在都可以實現需求的情況下盡量選擇多表查詢。
原因:子查詢會操作兩次,多表查詢只操作一次。多表的效率高。
但要注意的是,多表查詢如果產生了笛卡爾集(語句上要注意條件的使用),則會出現嚴重的效率問題。
一般不在子查詢中使用排序(order by),但在top-N分析問題中必須在子查詢中使用排序。
?
偽列
什么是偽列
- 偽列是在ORACLE中的一個虛擬的列。
- 列的數據是由ORACLE進行維護和管理的,用戶不能對這個列修改,只能查看。
- 所有的偽列要得到值必須要顯式的指定。
?
最常用的兩個偽列:rownum和rowid。
?
ROWNUM
ROWNUM(行號):是在查詢操作時由ORACLE為每一行記錄自動生成的一個編號。
每一次查詢ROWNUM都會重新生成。(查詢的結果中Oracle給你增加的一個編號,根據結果來重新生成)
rownum永遠按照默認的順序生成。(不受orderby的影響)
rownum只能使用< <=,不能使用> >=符號,原因是:Oracle是基于行的數據庫,行號永遠是從1開始,即必須有第一行,才有第二行。
行號的產生
【示例】需求:查詢出所有員工信息,并且顯示默認的行號列信息。
| --需求:查詢出所有員工信息,并且顯示默認的行號列信息。 SELECT ROWNUM,t.* FROM emp t;--* 和指定的列一起顯示的時候,必須加別名 |
提示兩點:
- ROWNUM是由數據庫自己產生的。
- ROWNUM查詢的時候自動產生的。
?
行號的排序
【示例】????
| --需求:查詢出所有員工信息,按部門號正序排列,并且顯示默認的行號列信息。 SELECT ROWNUM,t.* FROM emp t ORDER BY deptno;--order by 的原理:將查詢結果(此時行號已經有了,已經和每一行數據綁定了)進行排序。 - --order by是查詢語句出來的結果之后再排序的,,rownu是在查詢出來結果的時候產生。order by不會影響到行號 --先排序,再查詢 SELECT ROWNUM,t.* FROM ( SELECT * FROM emp ORDER BY deptno ) t |
結論:
order by排序,不會影響到rownum的順序。rownum永遠按照默認的順序生成。
所謂的"默認的順序",是指系統按照記錄插入時的順序(其實是rowid)。
利用行號進行數據分頁-重點
回顧mysql如何排序?
| select * from table limit m,n 其中m是指記錄開始的index,從0開始,表示第一條記錄 n是指從第m+1條開始,取n條。 select * from tablename limit 3,3 即取出第4條至第6條,3條記錄 |
Oracle如何分頁呢?
結論:Mysql使用limit的關鍵字可以實現分頁,但Oracle沒有該關鍵字,無法使用該方法進行分頁。
【示例】需求:根據行號查詢出第四條到第六條的員工信息。
| --需求:根據行號查詢出第四條到第六條的員工信息。 SELECT ROWNUM,t.* FROM emp t; SELECT ROWNUM,t.* FROM emp t WHERE ROWNUM >=4 AND ROWNUM<=6; --rownum只能使用< <=,不能使用> >=符號,原因是:Oracle是基于行的數據庫,行號永遠是從1開始,即必須有第一行,才有第二行。 SELECT ROWNUM,t.* FROM emp t WHERE ROWNUM<=6; --方案:可以使用子查詢 SELECT rownum,t2.* FROM ( SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM<=6--此時子查詢的rownum已經變成了虛表的一個列 ) t2--盡量讓虛表盡量小 WHERE t2.r >=4 ? --需求:要分頁查詢,每頁3條記錄,查詢第二頁 /* pageNum=2 pageSize=3 ? 計算: firstIndex=pageSize*(pageNum-1); maxCount=pageSize; ? mysql: limit 起始索引firstIndex,最大記錄數maxCount ? Oracle: //起始行號 firstRownum=pageSize*(pageNum-1)+1 //結束行號 endRownum=firstRownum+pageSize-1 ? 具體計算: firstRownum=3*(2-1)+1=4; endRownum=4+3-1=6; */ --寫Oracle的分頁,從子查詢寫起,也就是說從小于等于寫起,或者說從endRownum寫起 SELECT ROWNUM ,t2.* FROM ( SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM <=6 ) t2 WHERE t2.r >=4; --優化 SELECT * FROM ( SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM <=6 ) WHERE r >=4; SELECT empno,ename,job FROM--結果指定字段 ( SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM <=6 ) WHERE r >=4; ? --按照薪資的高低排序再分頁 SELECT * FROM ( SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM <=6 ORDER BY sal DESC ) WHERE r >=4 ; ? SELECT * FROM emp ORDER BY sal DESC; --先排序薪資,再分頁 SELECT * FROM ( SELECT ROWNUM r,t.* FROM (SELECT * FROM emp ORDER BY sal DESC) t WHERE ROWNUM <=6 ORDER BY sal DESC ) WHERE r >=4 ;--Hibernate會自動將所有數據封裝到實體對象(多余出來的行號那一列不會封裝) --如果不需要額外的字段,則只需要指定特定的列名就可以了。 --優化:子查詢字段盡量少一些。數據量少。比如,表中有100個字段,但你就想顯示5個,那么,你就子查詢中直接指定5個就ok了。但,使用orm框架的建議都查出來。 SELECT * FROM ( SELECT ROWNUM r,t.* FROM (SELECT ename,job,sal FROM emp ORDER BY sal DESC) t WHERE ROWNUM <=6 ORDER BY sal DESC ) WHERE r >=4 ; --通用 SELECT * FROM ( SELECT ROWNUM r,t.* FROM (SELECT ename,job,sal FROM emp ORDER BY sal DESC) t WHERE ROWNUM <=endRownum ORDER BY sal DESC ) WHERE r >=firstRownum ; ? /* 另外一種計算方法(索引算法) firstIndex=pageSize*(pageNum-1); endRownum=firstIndex+pageSize; */ SELECT * FROM ( SELECT ROWNUM r,t.* FROM (SELECT ename,job,sal FROM emp ORDER BY sal DESC) t WHERE ROWNUM <=endRownum ORDER BY sal DESC ) WHERE r > firstIndex;--Hibernate的內置算法 ? ? 2016-10-22 ? ? ----需求:要分頁查詢,每頁3條記錄,查詢第二頁 /* ? mysql: select * from emp limit 3,3; ? ? page = 2; pageSize = 3; ? ? firstIndex = (page-1)*pageSize; ? maxCount = pageSize; ? select * from emp limit firstIndex,maxCount; ? ? oracle: ? ? page = 2; pageSize = 3; ? startRowNum = (page-1)*pageSize+1; ? endRowNum = pageSize*page ? ? ? select * from (select rownum r,t.* from emp t where rownum<=endRowNum) where r>=startRowNum; ? ? ? ----按照薪資的高低排序再分頁 ? ? */ ? ? SELECT *FROM emp ORDER BY sal DESC; ? SELECT ROWNUM,t.* FROM(SELECT *FROM emp ORDER BY sal DESC) t WHERE ROWNUM<=6; ? SELECT * FROM (SELECT ROWNUM r,t.* FROM(SELECT *FROM emp ORDER BY sal DESC) t WHERE ROWNUM<=6) t2 WHERE t2.r>=4; |
分析原因:
rownum只能使用< <=,不能使用> >=符號,原因是:Oracle是基于行的數據庫,行號永遠是從1開始,即必須有第一行,才有第二行。
?
【提示】:
- 如何記憶編寫Oracle的分頁?建議寫的時候從里到外來寫,即先寫小于的條件的子查詢(過濾掉rownum大于指定值的數據),再寫大于的條件的查詢(過濾掉rownum小于的值)。
- Oracle的分頁中如果需要排序顯示,要先排序操作,再分頁操作。(再嵌套一個子查詢)
- 性能優化方面:建議在最里層的子查詢中就直接指定字段或者其他的條件,減少數據的處理量。
?
ROWID
ROWID(記錄編號):是表的偽列,是用來唯一標識表中的一條記錄,并且間接給出了表行的物理位置,定位表行最快的方式。
?
- 主鍵:標識唯一的一條業務數據的標識。主鍵是給業務給用戶用的。不是給數據庫用的。
- 記錄編號rowid:標識唯一的一條數據的。主要是給數據庫用的。類似UUID。
ROWID的查看
【示例】
| SELECT t.*,ROWID FROM emp t; |
?
ROWID的產生
使用insert語句插入數據時,oracle會自動生成rowid并將其值與表數據一起存放到表行中。
這與rownum有很大不同,rownum不是表中原本的數據,只是在查詢的時候才生成的。
提示:rownum默認的排序就是根據rowid
ROWID的作用
這里列舉兩個常見的應用:
- 去除重復數據。--面試題—了解
- 在plsql Developer中,加上rowid可以更改數據。
?
關于主鍵和rowid的區別:
相同點:為了標識唯一一條記錄的。
不同點:
主鍵:針對業務數據,用來標識不同的一條業務數據。
rowid:針對具體數據的,用來標識不同的唯一的一條數據,跟業務無關。
?
?
【示例】需求:刪除表中的重復數據,要求保留重復記錄中最早插入的那條。(DBA面試題)
| --查看rowid SELECT t.*,ROWID FROM emp t; --需求:刪除表中的重復數據,要求保留重復記錄中最早插入的那條。(DBA面試題) --準備測試表和測試數據: --參考建表語句如下: -- Create table create table test ( id number, name varchar2(50) ) ; --插入測試數據 INSERT INTO TEST VALUES(1,'xiaoming'); INSERT INTO TEST VALUES(2,'xiaoming'); INSERT INTO TEST VALUES(3,'xiaoming'); COMMIT; SELECT * FROM TEST ; --通過rowid,剔除重復xiaoming,保留最早插入的xiaoming SELECT t.*,ROWID FROM TEST t; --刪除的的時候,可以先查詢你要刪除的東東 SELECT t.*,ROWID FROM TEST t WHERE ROWID > (SELECT MIN(ROWID) FROM TEST); DELETE FROM TEST t WHERE ROWID > (SELECT MIN(ROWID) FROM TEST); ? --語句有缺點:條件不足,會只保留一條數據,誤刪其他數據 --重新插入測試數據 INSERT INTO TEST VALUES(1,'xiaoming'); INSERT INTO TEST VALUES(2,'xiaoming'); INSERT INTO TEST VALUES(3,'xiaoming'); INSERT INTO TEST VALUES(4,'Rose'); INSERT INTO TEST VALUES(5,'Rose'); COMMIT; --剔除重復數據 SELECT * FROM TEST WHERE ROWID NOT in(SELECT MIN(ROWID) FROM TEST GROUP BY NAME); DELETE TEST WHERE ROWID NOT in(SELECT MIN(ROWID) FROM TEST GROUP BY NAME); |
?
注意:刪除重復記錄一定要小心,萬一你的條件有問題,就會刪錯數據.建議刪除之前,可以先用查詢查一下,看是否是目標數據。
數據一旦刪除恢復比較麻煩,但可以恢復,采用日志回滾。一般不要輕易用。
?
數據處理
說完了所有的查詢,下面說說增、刪、改。
Update
- 使用工具進行更新數據的操作。(通過rowid偽列)
通過工具修改數據
提示:是否能使用工具修改,主要看語句有沒有rowid。
?
Insert
批量插入
語法:
| INSERT INTO table VALUES--單條插入語法 INSERT INTO table SELECT查詢語句--批量插入語法(主要用于將一張表中的數據批量插入到另外一張表中) |
?
【示例】需求:將dept表中部門名稱不為空的數據都插入到test表中
| --需求:將dept表中部門"名稱"不為空的數據都插入到test表中 INSERT INTO TEST(ID,NAME) SELECT deptno,dname FROM dept;--select的結果必須能插入到目標表中。(字段個數要對應、字段類型要對應) INSERT INTO TEST SELECT deptno,dname FROM dept ;--必須前后字段對應 --非法使用批量插入 INSERT INTO TEST SELECT deptno,dname,loc FROM dept ; |
?
Delete
Delete和truncate區別-面試題
- delete逐條刪除,truncate先摧毀表,再重建 。
- 最根本的區別是:delete是DML(可以回滾,還能閃回),truncate是DDL(不可以回滾 ,后面的所事務會講回滾)
- Delete不會釋放空間,truncate會(當確定一張表的數據不再使用,應該使用truncate)
- delete會產生碎片,truncate不會。
友情提示:面試經常會被問道。
?
Hwm-高水位
高水位線英文全稱為high water mark,簡稱HWM,那什么是高水位呢?
在Oracle數據的存儲中,可以把存儲空間想象為一個水庫,數據想象為水庫中的水。水庫中的水的位置有一條線叫做水位線,在Oracle中,這條線被稱為高水位線(High-warter mark, HWM)。在數據庫表剛建立的時候,由于沒有任何數據,所以這個時候水位線是空的,也就是說HWM為最低值。當插入了數據以后,高水位線就會上漲,但是這里也有一個特性,就是如果你采用delete語句刪除數據的話,數據雖然被刪除了,但是高水位線卻沒有降低,還是你剛才刪除數據以前那么高的水位。也就是說,這條高水位線在日常的增刪操作中只會上漲,不會下跌。
?
【高水位對Oracle的應用有什么影響呢?】
高水位對查詢有巨大的影響。而且還浪費空間。
?
【解讀Oracle中Select語句的特性】
極端例子:數據庫有10w條數據,刪掉了前面的99999個,我select查詢的時候,還是需要掃描10w次,雖然表中只有一條數據。效率還是非常的低!!!!!
?
如何解決高水位帶來的查詢效率問題呢?
?
?
【示例】查看、測試、消除高水位—了解
| --之前查看rowid SELECT t.*,ROWID FROM TEST t; ? --對表進行分析,收集統計信息(執行了收集信息的動作,user_tables表的塊字段才有數據) analyze table TEST compute statistics; --查詢表數據的塊信息,其中blocks是高水位,empty_blocks是預申請的塊空間。 select table_name,blocks,empty_blocks from user_tables where table_name='TEST'; --收縮表(整理碎片),降低高水位,消除行移植和行鏈接,不釋放申請的空間 ALTER TABLE TEST MOVE; ? --對表進行分析,收集統計信息(執行了收集信息的動作,user_tables表的塊字段才有數據) analyze table TEST compute statistics; --查詢表數據的塊信息,其中blocks是高水位,empty_blocks是預申請的塊空間。 select table_name,blocks,empty_blocks from user_tables where table_name='TEST'; ? --之后查看rowid SELECT t.*,ROWID FROM TEST t; |
結論:
- 收縮表之后,高水位線下降了。
- 收縮表之后,rowid發生了變化。
?
注意:
- move最好是在空閑時做,記得move的是會產生鎖的(如果你move的時候需要很長事件,那么別人是不能操作這張表的。排他鎖)
- move以后記得重建index(后續講到索引,你會知道索引存放的其實就是數據的地址信息。當數據的地址變動了,索引也會失效。)語法:ALTER INDEX 索引名字 REBUILD;
?
數據庫事務
什么是數據庫事務?
事務是保持數據的一致性,它由相關的DDL或者DML語句做為載體,這組語句執行的結果要么一起成功,要么一起失敗。
?
事務的特性
SQL92標準定義了數據庫事務的四個特點(ACID):
原子性 (Atomicity) :一個事務里面所有包含的SQL語句是一個執行整體,不可分割,要么都做,要么都不做
一致性 (Consistency) :事務開始時,數據庫中的數據是一致的,事務結束時,數據庫的數據也應該是一致的
隔離性 (Isolation): 多個事務并發的獨立運行,而不能互相干擾,一個事務修改,新增,刪除數據在根據當前事務的事務隔離級別基礎上,其余事務能看到相應的結果(這里為什么這么說,下面我會給我具體的例子進行分析)
持久性 (Durability) : 事務被提交后,數據會被永久保存
?
事務的開始和結束
Oracle的默認事務開啟和結束是跟mysql不一樣的。
回顧:mysql的事務是如何開啟的?
MySQL默認采用autocommit模式運行。這意味著,當您執行一個用于更新(修改)表的語句之后,MySQL立刻把更新存儲到磁盤中,不需要手動提交。
如果需要手動管理事務,需要顯式的關閉自動事務:Set autocommit false,然后顯式的手動開啟事務:START TRANSACTION,直到手動COMMIT或ROLLBACK結束事務為止。
?
那么,Oracle的事務是如何開啟的?
Oracle的事務默認是手動管理事務,事務是自動開啟(不需要顯式的開啟,隱式開啟),但一般需要手動提交關閉。
?
Oracle事務的開始和結束的觸發條件:
- 事務的開始:以第一個DML語句(insert update delete)的執行作為開始,即是自動開啟的事務。
- 事務的結束(以下條件之一):
- 顯式結束:commit, rollback(還是隱式commit)
- 隱式結束(自動提交):DDL(create table…)和DCL(所以不能回滾 ),exit(事務正常退出)
- 隱式回滾(系統異常終止):關閉窗口,死機,掉電。
?
工具上的事務按鈕:
?
隱式提交:
?
提示:一般情況下,我們盡量使用手動提交事務。
?
控制事務-保留點SAVEPOINT—了解
事務過程中是可以控制的,通過SAVEPOINT語句。
SAVEPOINT的作用:
- 使用 SAVEPOINT 語句在當前事務中創建保存點,語法:SAVEPOINT 保留點名稱。
- 使用 ROLLBACK 語句回滾到創建的保存點。語法:ROLLBACK TO 保留點名稱。
?
【示例演示】
| SELECT * FROM TEST; INSERT INTO TEST VALUES(85,NULL); SELECT * FROM TEST; SAVEPOINT aa;--保留點 INSERT INTO TEST VALUES(86,NULL);--后悔了,不插入了 SELECT * FROM TEST; --回滾 ROLLBACK TO aa; SELECT * FROM TEST; INSERT INTO TEST VALUES(87,NULL); SELECT * FROM TEST; --提交 COMMIT; SELECT * FROM TEST; |
?
注:
當前事務提交后,事務中所有的保存點將被釋放。
?
JAVA中也有關于保留點的API,
具體調用采用Connection對象來操作它,相關方法如下:
?
?
數據庫對象-表(TABLE)
什么是數據庫對象?
數據庫對象,是數據庫的組成部分,有表(Table )、索引(Index)、視圖(View)、用戶(User)、觸發器(Trigger)、存儲過程(Stored Procedure)、圖表(Diagram)、缺省值(Default)、規則(Rule)等。
表的命名規則和命名規范
表名和列名的基本規范如下:
【擴展】
另外,每個公司都有自己特有的命名規范,比如,要求所有的數據庫對象都要加上一個前綴,用于快速識別對象的類別。
比如表的命名:
t_person :存放個人信息的表。
t_crm_person:存放客服子系統模塊的人員信息表。
視圖的命名:
v_person:用來查詢人員信息的視圖。
?
命名規范的作用:
- 良好的命名規范便于識別和管理,對于系統開發和維護都有很大的幫助。
- 使用工具的提示功能也更容易快速定位到所需要的對象。
?
創建表CREATE TABLE
基本語法
創建表的要求條件:
- 必須具備CREATE TABLE權限、存儲空間。
- 必須指定表名、列名、數據類型、數據類型的大小
?
復制表
語法:
Create table 新表 as select from 舊表 條件(如果條件不成立,則只復制結構,如果條件成立,復制結構和值)
?
?
使用子查詢創建表,而且還可以將創建表和插入數據結合起來。
【示例】
--復制一張和原來一模一樣的新表,包含數據
| --復制一張和原來一模一樣的新表,包含數據 CREATE TABLE t_dept AS SELECT * FROM dept; SELECT * FROM t_dept ? --復制一張和原來一模一樣的新表,不要數據,只要結構 CREATE TABLE t_dept_empty AS SELECT * FROM dept WHERE 1<>1; SELECT * FROM t_dept_empty; ? ? ---t_dept,在現網(正式環境)確實要測試一下數據.一般我們可以在建立一張和這個一模一樣的表.c ? --能不能只復制部分字段建立新表?可以! --復制表的部分字段 CREATE TABLE t_dept_part AS SELECT deptno,dname FROM dept; SELECT * FROM t_dept_part; |
?
提示:
復制表有沒有數據的區別,是select子句結果有沒有數據。如果子句結果沒有數據,則僅創建表,如果有數據,則創建表的同時也插入符合條件的數據。
?
注意:
- 指定的列和子查詢中的列要一一對應
- 通過列名和默認值定義列
關于where 1=1的寫法,一般我們用來拼湊條件的。
1<>1是為了營造一個永遠不成立的條件。
?
Oracle的數據類型
?
修改表ALTER TABLE
基本語法
修改表的列:
?
修改表的列的能力:
- 追加新的列
- 修改現有的列
- 刪除一個列
?
修改對象的名稱:
作用:
- 執行RENAME語句改變表, 視圖, 序列, 或同義詞的名稱。
- 要求必須是對象的擁有者
【示例】
| RENAME t_dept TO t_dept_new; Table renamed. |
?
通過工具來修改表
操作方式:
?
刪除表DROP TABLE
基本語法
注意:
- 數據和結構都被刪除。
- 所有正在運行的相關事物被提交。(ddl語句)
- 所有相關索引被刪除。(表附屬對象會被刪除)
- DROP TABLE 語句不能回滾,但是可以閃回。
?
完整的oracle數據庫的版本的情況下,普通用戶刪除的表,會自動放入回收站
你可以從回收站還原(閃回)。
?
友情提示:
日常操作中,刪除操作一定要小心,一旦刪除了且沒有放入回收站,則意味著數據的丟失!
記住一句話:數據無價!!!
約束
約束的概念作用
- 約束是可以更好的保證數據庫數據的完整性和一致性的一套機制。
- 約束可以限制加入表的數據的類型。
- 如果存在依賴關系,約束可以防止錯誤的刪除數據,也可以級聯刪除數據。
?
數據庫的約束可以認為是對表的數據的一種規則。
約束創建的時機
- 創建表的時候,同時創建約束。
- 表結構創建完成后,可以再添加約束。
常見的約束類型
- NOT NULL
- UNIQUE
- PRIMARY KEY
- FOREIGN KEY
- DEFAULT
- CHECK—用來檢查一個字段的值是否符合某表達式,表達式的結果必須是布爾值。
?
其中:check約束是Oracle特有的約束。
?
通過工具快速添加約束
?
通過工具快速得到SQL的代碼:
插入數據測試Check約束
?
?
約束的應用選擇
在應用開發中,主鍵約束一般要設置,其他如非空、唯一、默認值、檢查等約束,可以根據實際情況來添加。而外鍵約束是否要設置,是存在一點爭議的。(爭議在性能上)
一般建議:
- 在大型系統中(性能要求不高,安全要求高),可以使用外鍵;在大型系統中(性能要求高,安全自己控制),不用外鍵;小系統隨便。
- 不用外鍵的話,可以用程序控制數據一致性和完整性,可以在代碼的數據層通過代碼來保證一致性和完整性。
- 用外鍵要適當,不能過分追求。
?
從JAVA開發的角度上說,一般不建議使用外鍵,除了性能外,使用程序控制業務更靈活。
比如客戶和訂單,這兩個之間的關聯雖然可以建立外鍵關系,實現級聯效果(如級聯刪除)。
- 如果有外鍵約束,則刪除客戶的時候,必須先刪除客戶下的訂單,否則,不允許刪除。
- 從數據完整一致性的角度上說,如果客戶被刪除了,訂單也無意義了,這是合理的。
- 但從業務角度上說,客戶被刪除了,是否意味這訂單也必須刪除呢?單純保留訂單的行為也是合理的。
?
序列-sequence
需求:
Mysql中主鍵有自增長的特性.
Oracle中,主鍵沒有自增長這個特性.那么如何解決這個問題.使用序列可以解決.
概念和作用
序列:可供多個用戶來產生唯一數值的數據庫對象
. 自動提供唯一的數值
. 共享對象
. 主要用于提供主鍵值
. 將序列值裝入內存可以提高訪問效率
?
這個是Oracle特色的。Mysql是沒有的。
簡單的說,他可以用來高效的生成主鍵值。
?
語法
將序列提前裝入內存,可以提高效率。
創建序列
【示例】
創建一個簡單的序列
| CREATE SEQUENCE seq_test; |
?
序列的使用
在ORACLE中為序列提供了兩個偽列:
?
【示例】
| 為什么? 原因是:序列初始化之后指針在第一個數之前。必須先向前移動才可以查詢的到。 數組的指針默認在1之前,并沒有指向第一個值,要想使用必須向前移動一下。(指針只能向前不能向后) [1,2,3….20][ * 操作指針: [1,2,3….20][ * ? SELECT seq_test.nextval FROM dual; 移動一位并且取值。 |
?
序列的應用
Oracle建表的時候是否能像mysql那樣設定一個自增長的列嗎?
不行!
那如何解決呢?使用序列!
?
【示例】在插入數據的時候插入序列主鍵.
| --在插入數據的時候插入序列主鍵. INSERT INTO TEST VALUES(seq_test.nextval,'Jack'); |
?
問題:為什么這個值不是從1開始?
原因: 共享對象 序列是個獨立對象.誰都能用,誰都能共享它.
?
序列的裂縫
2,當插入記錄時報錯,序列對象值也被使用,下一次再使用時,序列的值就會+1
?
【示例】序列的裂縫
| INSERT INTO T_TESTSEQ VALUES(seq_test.nextval,'張三1'); ROLLBACK; INSERT INTO T_TESTSEQ VALUES(seq_test.nextval,'張三2'); COMMIT; SELECT * FROM T_TESTSEQ; |
也就是說,用序列插入數據庫的值不一定是連續的。
補充:
Mysql的自增長列也可以是不連續的.
?
序列出現裂縫的條件:
- 事務回滾。
- 系統異常。
- 多個表同時使用同一個序列。
?
這個序列是公用的對象。如果你很在意的話,就一個表用一個序列,但大多數情況下,這個主鍵值(代理主鍵)沒有什么意義的話,可以多個表公用一個序列。
?
Oracle的體系結構-了解
Oracle數據庫和Oracle實例
Oracle 服務器軟件部分由兩大部分組成, Oracle 數據庫 和 Oracle 實例。
兩者的解釋如下:
- Oracle 數據庫(物理概念): 位于硬盤上實際存放數據的文件和相應的程序文件, 這些文件組織在一起, 成為一個邏輯整體, 即為 Oracle 數據庫. 因此在 Oracle 看來, "數據庫" 是指硬盤上文件的邏輯集合, 必須要與內存里實例合作, 才能對外提供數據管理服務。
- Oracle 實例(邏輯概念): 位于物理內存里的數據結構. 它由一個共享的內存池和多個后臺進程所組成, 共享的內存池可以被所有進程訪問. 用戶如果要存取數據庫(也就是硬盤上的文件) 里的數據, 必須通過實例才能實現, 不能直接讀取硬盤上的文件。實例的唯一標識也稱之為SID(OSID)。
?
一個實例只能對應一個數據庫,一個數據庫可以有多個實例(RAC集群),但大多數情況下, 一個數據庫上只有一個實例對其進行操作。我們就是通過連接到實例來操作數據庫的。
?
Oracle常見的存儲文件
常見的存儲文件主要為三類:
- 數據文件。存儲數據用的。
例:表
- 控制文件。記錄數據文件存放的位置。例:數據庫名稱、數據文件名稱及位置。
- 日志文件。記錄數據信息變化的。例:因故障問題造成一些數據沒有及時寫入到數據文件,可以使用日志文件恢復(Oracle日志回滾:如果你的數據被delete掉并且提交了,數據還是可以恢復的,可以通過日志來恢復的)。
?
表空間(Tablespace)的管理
表空間的概念
ORACLE是屬于文件存儲。ORACLE中的數據是存放在一個個數據文件中,數據文件存放在磁盤中。
如果說數據文件是物理概念,那么表空間就是邏輯概念,Oracle通過表空間來對數據文件中的數據進行CRUD。
表空間是一種邏輯結構,是Oracle最大的邏輯單元,可以理解為:所有的數據都存儲在表空間中。
表空間的屬性特點:
- 一個數據庫可以包含多個表空間,一個表空間只能屬于一個數據庫。
- 一個表空間可以由一個或多個數據文件組成,一個數據文件只能屬于一個表空間。
- 表空間可以劃分成更細的邏輯存儲單元。(了解)
?
數據庫的存儲結構--了解
官方數據存儲結構圖:
各對象之間的存儲對應關系圖:
- 所有的數據庫對象都存儲在表空間中,而表空間被數據庫服務管理。
- 一個表空間可以對應N個數據文件,表空間是邏輯概念,而數據文件是物理概念。
- 方案(SCHEMA模式)是表、視圖、索引等數據庫對象的邏輯集合,它通過數據庫服務來間接管理這些對象。
- 一個用戶(user)創建時會同時創建一個同名的方案(schema),即,你甚至可以認為用戶和方案是同一個東西(事實上不是,用戶主要是做權限等相關管理的)。當用戶登錄后,就立刻擁有了該同名方案下所有對象。
- 方案(用戶)和表空間沒有什么必然關系,一個方案擁有一個默認的表空間,但同時可以使用多個表空間來存儲它的對象。一個表空間可以為不同的方案來存儲其所屬對象
?
【補充閱讀】下面有個很形象的比喻,是從網上摘的,不妨一看:
我們可以把database看做是一個大倉庫,倉庫分了很多很多的房間,schema就是其中的房間,一個schema代表一個房間,table可以看做是每個schema中的床,table被放入每個房間中,不能放置在房間之外,那豈不是晚上睡覺無家可歸了,然后床上可以放置很多物品,就好比table上可以放置很多列和行一樣,數據庫中存儲數據的基本單元是table,顯示中每個倉庫放置物品的基本單位就是床,user就是每個schema的主人,(所以schema包含的是object,而不是user),user和schema是一一對應的,每個user在沒有特別指定下只能使用自己schema的東西,如果一個user想使用其他schema的東西,那就要看那個schema的user有沒有給你這個權限了,或者看這個倉庫的老大(DBA)有沒有給你這個權限了。換句話說,如果你是某個倉庫的主人,那么這個倉庫的使用權和倉庫中的所有東西都是你的,你有完全的操作權,可以扔掉不用東西從每個房間,也可以防止一些有用的東西到某個房間,你還可以給每個user分配具體的權限,也就是他到某一個房間能做些什么,是只能看(read-only),還是可以像主人一樣有所有控制權(R/W),這個就要看這個user所對應的角色Role了。
?
作業: 課后了解 用戶和方案的關系
?
數據操作的過程:
【小結】
表空間:屬于一種邏輯結構。記錄物理文件的邏輯單位。是Oracle最大的邏輯單位.
也就是說,我們所有的數據都存儲在表空間中.
?
常見的表空間分類—了解
- (永久)數據表空間,主要用來永久存儲正式的數據文件。
- 臨時數據表空間,主要用來存儲臨時數據的,比如數據的排序、分組等產生的臨時數據,不能存放永久性對象。
- UNDO表空間,保存數據修改前的鏡象。
?
臨時表空間和UNDO表空間的異同:(了解)
- 相同之處:兩者都不會永久保存數據。
- 不同之處:UNDO表空間用于存放UNDO數據,當執行DML操作時,oracle會將這些操作的舊數據寫入到UNDO段,以保證可以回滾和事務隔離讀取等,主要用于數據的修改等;而臨時表空間主要用來做查詢和存放一些緩沖區數據。
Oracle對表空間的管理方式—了解
字典管理:全庫所有的空間分配都放在數據字典中。容易引起字典爭用,而導致性能問題。
本地管理:空間分配不放在數據字典,而在每個數據文件頭部的第3到第8個塊的位圖塊,來管理空間分配。oracle公司推薦使用本地管理表空間。
?
表空間的創建
注:表空間的創建一般是由DBA來操作完成的,而且需要管理員權限(我們一般用sys)。
三種表空間中,UNDO表空間通常是由Oracle自動化管理的,而另外兩種表空間則一般需要手動創建。
【常用參數語法】:
| --創建永久數據表空間 CREATE TABLESPACE TABLESPACE_NAME [DATAFILE DATAFILE1,[DATAFILE 2]…] [LOGGING | NOLOGGING] [ONLINE|OFFLINE] [EXTENT_MANAGEMENT_CLAUSE] ? 參數說明:
? --創建臨時數據表空間 CREATE TEMPORARY TABLESPACE TABLESPACE_NAME TEMPFILE DATAFILE1,[DATAFILE 2]… EXTENT_MANAGEMENT_CLAUSE 參數說明:
|
【最簡語法】
| Create tablespace 表空間名稱 表空間類型 '物理文件全路徑' Size 初始文件大小 |
?
【示例】
永久數據表空間和臨時數據表空間的建立。
| --建立一個數據表空間。 CREATE TABLESPACE tbl_itcast_dat DATAFILE 'D:\Applications\Oracle\mydata\itcast_dat01.dbf' SIZE 50m AUTOEXTEND ON NEXT 5m MAXSIZE 2000m EXTENT MANAGEMENT LOCAL ? --創建臨時數據表空間。 CREATE TEMPORARY TABLESPACE tbl_itcast_tmp TEMPFILE 'D:\Applications\Oracle\mydata\itcast__tmp.dbf' SIZE 20m EXTENT MANAGEMENT LOCAL |
?
解釋:
?
?
【提示】:
文件路徑(data目錄)必須提前存在,否則:
?
注意:
實際企業開發中,不要用最簡化的方式來進行表空間的創建。
【參考示例1】
| --創建數據表空間 CREATE TABLESPACE TBS_CSP_BS_DAT DATAFILE '/dev/rlv_dat001' SIZE 2000M REUSE AUTOEXTEND OFF, LOGGING ONLINE PERMANENT EXTENT MANAGEMENT LOCAL; --創建臨時數據表空間 CREATE TEMPORARY TABLESPACE TBS_CSP_BS_TMP TEMPFILE '/dev/rlv_dat009' SIZE 2000M REUSE AUTOEXTEND OFF EXTENT MANAGEMENT LOCAL UNIFORM SIZE 10M; |
注:
PERMANENT是顯式的指定創建的是永久的表空間,用來存放永久對象。默認值。
【參考示例2】
| --創建數據表空間 create tablespace tbs_user_data logging datafile 'D:\oracle\oradata\Oracle9i\user_data.dbf' size 50m autoextend on next 50m maxsize 20480m extent management local; --創建臨時數據表空間 create temporary tbs_user_temp tempfile 'D:\oracle\oradata\Oracle9i\user_temp.dbf' size 50m autoextend on next 50m maxsize 20480m extent management local; |
?
刪除表空間
語法:
| DROP TABLESPACE |
?
?
【示例】
| --刪除表空間以及下面所有數據和數據文件(全刪,寸草不生) DROP TABLESPACE tbl_itcast_tmp INCLUDING CONTENTS AND DATAFILES; |
| 提示:如果不加后面的一堆,則,只是將表空間進行了邏輯刪除(Oracle無法管理使用這個表空間了,但數據文件還存在)。 |
?
表空間的一個應用
【示例】
建立表的時候指定表空間。
?
企業開發中,一定不要用默認的表空間,一定使用要指定表空間。
最簡的一個建表腳本:
注意:
寫建表的語句的時候,可以指定存儲的表空間,但不建議指定表空間的參數。
?
用戶和權限
用戶角色權限的關系
預備知識:
預定義用戶(賬戶)
Oracle預定義有很多用戶,用于不同的用途。這些用戶大都默認是禁用的(如scott,hr等),但有兩個最重要的用戶是默認開啟的,這兩個用戶就是SYS和SYSTEM。
?
- SYS 帳戶(數據庫擁有者):
- 擁有 DBA 角色權限
- 擁有 ADMIN OPTION 的所有權限
- 擁有 startup, shutdown, 以及若干維護命令
- 擁有數據字典
- SYSTEM 帳戶
- 擁有 DBA 角色權限.
?
注意:這些帳戶通常不用于常規操作。
?
Sys和system賬戶的區別:
- sys用戶是數據庫的擁有者,是系統內置的、權限最大的超級管理員帳號。
- system用戶只是擁有DBA角色權限的一個管理員帳號,其實它還是歸屬于普通用戶。
?
操作用戶
- 創建用戶的語句
create user 用戶名
identified by 密碼(不要加引號)
default tablespace 默認表空間名 quota 5M on 默認表空間名
[temporary tablespace 臨時表空間名]
[profile 配置文件名] //配置文件
[default role 角色名] //默認角色
[password expire] //密碼失效
//如果設置失效,那么第一次登錄的時候,會提醒你更改密碼。
[account lock] //賬號鎖定(停用)
- 修改用戶
alter user 用戶名 identified by 密碼 quota 10M on 表空間名
alter user 用戶名 account lock/unlock
- 刪除用戶
drop user 用戶名 [cascade].如果要刪除的用戶中有模式對象,必須使用cascade.
?
【示例】最簡方式創建一個用戶
| 切換到sys用戶下: |
注:未指定的參數都采用默認值。
?
【示例】借助工具創建一個用戶
| ? 創建用戶的時候指定的表空間,會成為以后在該用戶下建立對象(表)的默認存儲表空間。 ? -- 語句:Create the user /*創建用戶并指定表空間 */ create user itcast19 identified by itcast19 default tablespace TBL_ITCAST19_DAT temporary tablespace TBL_ITCAST19_TMP; --上鎖解鎖改密碼等 |
?
注意:
一般企業開發中,建表要手動指定表空間,可以讓不同模塊、不同功能的對象存儲在不同的數據文件中,可以提高性能。
?
?
【示例】刪除用戶
| --刪除用戶及其下面所有的對象 drop user itcasttest cascade; |
?
提示,每個數據庫用戶帳戶具備:
- 一個唯一的用戶名
- 一個驗證方法
- 一個默認的表空間
- 一個臨時表空間
- 權限和角色
- 每個表空間的配額.
?
配置角色和權限
使用上面創建的用戶登錄測試:
結果報錯。
提示說:該用戶沒有創建會話的權限,登錄被拒絕。
?
那該如何賦權呢?賦什么權限呢?
Oracle內置有大量的權限屬性:
常見權限:
我們可以將create session權限賦權給新建的用戶.新建的用戶就可以登錄了.
我們再建立一張表看看:
結果又提示是權限不足。= =...
再添加建表的權限:
再次測試建表:
再添加一條數據看看:
竟然又沒有權限!
。。。
結論:這樣一個個添加權限非常的麻煩!
是否可以使用比較簡單的方式將普通用戶的權限賦予給一個用戶呢?
可以!通過預定義內置角色就可以實現。
?
需要分配 unlimited tablespaces 權限
如何選擇預定義的角色呢?
普通用戶就選擇:connect和Resource角色即可。
管理員用戶選擇:connect和Resource、dba角色。
?
| /*給用戶授予權限 */ grant connect,resource to username; |
再次登錄、各種操作測試,均正常了!
?
【提示】
如果遇到這個錯誤:
說明當前用戶沒有操作該表空間的權限,需要手動加入這個權限:
????
?
梳理回顧建立一個普通用戶的過程:
1.創建用戶—2.賦權限(connect和resourece角色)
?
Oracle用戶(user)和方案(schema)
幾個概念:
- 方案就是屬于某一用戶的所有對象(表、視圖等)的集合.
- 用戶名和方案名往往是通用的.
- 一個用戶只能關聯一個方案.
- 創建用戶時系統會自動創建一個同名方案(schema)
?
提示:
Scott用戶的方案名也是scott,因此,后面我們將這兩個概念放在一起用,即我們可以說,某表是scott用戶下的對象,也可以說是scott方案下的對象。
?
?
跨域訪問對象
跨域訪問也稱之為跨用戶訪問、跨方案訪問,訪問的方式為:用戶名.對象名,
?
如在itcast用戶下訪問scott用戶下的emp表的數據:
Select * from scott.emp;
原因:沒有對象訪問權限。
?
?
Oracle用戶的權限分為兩種:
- 系統權限(System Privilege): 允許用戶執行對于數據庫的特定行為,例如:創建表、創建用戶等
- 對象權限(Object Privilege): 允許用戶訪問和操作一個特定的對象,例如:對其他方案下的表的查詢
?
?
【示例】需求:itcast用戶要讀取scott用戶中emp表的數據。
| --scott用戶登錄賦權: --Sql語句: ? --itcast用戶登錄測試: |
?
注意:
賦權的時候,只能是自己擁有的權限、或者該權限是可以傳遞的,才可以將其賦予別人。
?
視圖VIEW
問題:
Itcast用戶現在只需要查詢10部門的員工數據就行了,scott也不想將所有數據都開放給itcast用戶。
視圖的概念和作用
概念:
- 視圖是一種虛表.
- 視圖建立在已有表的基礎上, 視圖賴已建立的這些表稱為基表。
- 向視圖提供數據內容的語句為 SELECT 語句, 可以將視圖理解為存儲起來的 SELECT 語句.
- 視圖向用戶提供基表數據的另一種表現形式
作用:
語法
?
語法: create VIEW 視圖名稱 as select ….
?
提示:
子查詢可以是任意復雜的 SELECT 語句。
?
語法詳細分析:
糾正:默認值不是只讀。
?
操作視圖
視圖只能創建、替換和刪除,不能修改。
創建視圖
【示例】創建10號部門的視圖
| --sql語句建立視圖 CREATE VIEW v_emp10 AS SELECT * FROM emp WHERE deptno=10 ; |
?
提示:如果提示權限不足而導致無法添加視圖,則需要添加權限,一般為學習方便,我們會直接添加dba角色權限。
| --切換到sys用戶下,為scott添加dba權限: |
?
查詢視圖
【示例】查詢視圖
?
?
【示例】視圖的真實內容查看
結論:
可以看出,視圖的本質就是sql語句。
替換視圖
視圖沒有修改功能。
【示例】要將視圖改為可以查詢10號部門的員工信息且工資要大于2000:
| CREATE OR REPLACE VIEW v_emp10 AS SELECT * FROM emp WHERE deptno=10 AND sal >2000; |
提示:
平時我們在編寫建立視圖的語句時候,一般直接把replace加上,即直接CREATE OR REPLACE。
?
刪除視圖
【示例】刪除10好部門的這個視圖
| DROP VIEW v_emp10; SELECT * FROM v_emp10; |
?
幾個參數說明
| ? --先創建視圖再創建表:一般用的不多,一般我們都是先有表再創建視圖。 CREATE OR REPLACE FORCE VIEW v_test2015 AS SELECT * FROM test2015; ? SELECT * FROM v_test2015 ? --視圖默認情況下和表一樣,擁有表類似的功能,可以crud SELECT t.*,ROWID FROM v_emp10 t; SELECT * FROM emp; CREATE OR REPLACE VIEW v_emp10 AS SELECT * FROM emp WHERE deptno=10 WITH CHECK OPTION;--數據的增加和修改,必須滿足子查詢的條件 ? --一般視圖,我們主要用來查詢的,一般不維護它。 CREATE OR REPLACE VIEW v_emp10 AS SELECT * FROM emp WHERE deptno=10 WITH READ ONLY; |
只讀視圖
一般情況下,視圖主要用來提供查詢的,并不希望用戶去修改它,因此,我們可以創建只讀視圖。創建只讀視圖只需要添加with read only 選項即可,這樣就可以屏蔽對視圖的DML操作。
【示例】將已有的視圖修改為只讀視圖
| CREATE OR REPLACE VIEW v_emp_dept10 AS SELECT * FROM emp WHERE deptno=10 AND sal >2000 WITH READ ONLY ; |
?
友情提示:
其實,很多大的系統中,比如銀行,某些客戶會告訴你,這個表存這個數據,那個表存哪個數據,但實際上,可能不是真正的表,而是視圖,而且還是只讀的。
為什么給視圖?原因是:
如果是存錢的表,那么放開給你,是不是非常危險。如果業務需要確實是需要更改這個表的數據呢?一般來調用存儲過程(一般有提供,有一定特定功能,還能記錄日志)來改表,為了安全!不能直接改表。
跨域訪問視圖
【示例】只放開scott下的emp表的部分數據給itcast14用戶查詢,開放的數據要求為:20號部門的員工,字段只顯示員工號和姓名,且要求這兩個字段的標題顯示為中文。(要求本例使用工具來操作)
| --在scott下創建視圖(視圖名稱參考為:v_emp_dept20) --將生成的腳本如下: create or replace view v_emp_dept20 as select empno "編號",ename "姓名" from emp where deptno=20 WITH READ ONLY; --scott下查詢驗證一下: SELECT * FROM v_emp_dept20; --將該視圖賦予itcast用戶:在scott用戶下操作: grant select on v_emp_dept20 to itcast; ? --切換到itcast用戶下進行查詢驗證: Select * from scott.v_emp_dept20; ? |
?
另外補充:
視圖可以屏蔽篩選不同字段、字段名稱等,因此,你看到的時候的字段也未必是真實表中存在的!
| CREATE OR REPLACE VIEW v_emp10 AS SELECT empno 編號,ename empname FROM emp WHERE deptno=10 WITH READ ONLY; |
?
?
視圖小結
視圖和表的區別:
視圖是實體表的映射,視圖和實體表區別就是于視圖中沒有真實的數據存在。
?
什么時候使用視圖:
?
注意:在企業中,你查詢的對象(表)他可能不是一張的表,可能是視圖;你看到的視圖的字段可能也不是真實的字段。
?
同義詞SYNONYM
問題:我們想偽裝一下這個視圖的名字,或者是嫌調用的這個對象名字太長,怎么辦?
同義詞的概念和作用
同義詞就是(對象的)別名,可以對表、視圖等對象起個別名,然后通過別名就可以訪問原來的對象了。
作用:
- 方便訪問其它用戶的對象
- 縮短對象名字的長度
?
語法
?
操作同義詞
同義詞只有創建和刪除操作。
【需求】在itcast用戶下為視圖scott.v_emp_dept20創建一個同義詞emp20;
| --查詢驗證: |
?
友情提示:
如果工作中,你遇到一張"表"來查詢數據,那么它一定是表么?不一定,可能是視圖,也可能是同義詞.
另外,任何對象都能起別名。下面的例子對emp表起個別名:
?
?
?
?
?
重點:
?
轉載于:https://www.cnblogs.com/beyondcj/p/6271086.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: ubuntu16.04安装evo
- 下一篇: 4W1T教程1 如何使用幻灯片