視圖、序列、索引、約束
1. 視圖
? 視圖定義
視圖(VIEW)也被稱作虛標,即虛擬的表,是一組數據的邏輯表示,其本質是對應於一條SELECT語句,結果集被賦予一個名字,即視圖名字。
視圖本身並不包含任何數據,它只包含映射到基表的一個查詢語句,當基表數據發生變化,視圖數據也隨之變化。
創建視圖語法:
CREATE [OR REPLACE] VIEW view_name [(alias[,alias…])] AS subquery; |
視圖創建後,可以像操作表一樣操作視圖,主要是查詢操作。
根據視圖所對應的子查詢種類分為:
l SELECT語句是基於單表建立的,且不包含任何函數運算、表達式或分組函數,叫做簡單視圖,此時視圖是基表的子集
l SELECT語句同樣是基於單表,但包含了單行函數、表達式、分組函數或GROUP BY 子句,叫做復雜視圖
l SELECT語句是基於多個表的,叫做連接視圖。
? 視圖作用
如果需要經常執行某項復雜查詢,可以基於這個復雜查詢建立視圖,此後查詢此視圖即可,簡化復雜查詢。
視圖本質上就是一條SELECT語句,所以當訪問視圖時,只能訪問所對應的SELECT語句中設計到的列,對基表中的其它列起到安全和保密的作用,可以限制數據訪問。
? 授權創建視圖
創建視圖的DDL語句是CREATE VIEW,用於必須有CREATE VIEW系統權限才能創建視圖。
案例:演示權限不足情況下創建視圖報錯如下
管理員通過DCL語句授予用戶創建視圖的權限,如下:
GRANT CREATE VIEW TO username; |
案例:授予SCOTT創建視圖權限
? 創建簡單視圖
案例:使用SCOTT用戶創建emp的視圖
CREATE VIEW v_emp AS SELECT empno,ename,sal,deptno FROM emp WHERE deptno=10; |
查看視圖:
DESC v_emp; |
? 查詢視圖
案例:查詢視圖
SELECT * FROM v_emp; |
? INSERT
視圖本身並不包含數據,只是基表數據的邏輯映射。所以當對視圖執行DML操作時,實際上是對基表的DML操作。對視圖執行DML操作基本原則如下:
l 簡單視圖能夠執行DML操作,下列情況除外:在基表中定義了非空列,但簡單視圖對應的SELECT語句並沒有包含這個非空列,導致這個非空列對視圖不可見,這時無法對視圖執行INSERT操作
l 如果視圖定義中包含了函數、表達式、分組語句、DISTINCT關鍵字或ROWNUM偽列,不允許執行DML操作
l DML操作不能違反基表的約束條件
案例:對簡單視圖進行INSERT操作
INSERT INTO v_emp VALUES (1000,‘QQQ‘,5000,10); |
查看視圖:
SELECT * FROM v_emp; |
查看基表:可以發現對基表產生了影響
SELECT * FROM emp; |
? CHECK OPTION約束
語法:
CREATE [OR REPLACE] VIEW view_name[(alias[, alias…])] AS subquery [WITH CHECK OPTION]; |
WITH CHECK OPTION表示通過視圖所做的修改,必須在視圖的可見範圍內:
l INSERT,新增的記錄在視圖仍可查看
l UPDATE,修改後的結果必須能通過視圖查看到
l DELETE,只能刪除現有視圖裏能看到的記錄
案例:創建帶有CHECK OPTION約束的視圖
CREATE OR REPLACE VIEW v_emp AS SELECT empno id,ename name,sal salary,deptno FROM emp WHERE deptno=10 WITH CHECK OPTION; |
? READ ONLY約束
對簡單視圖進行DML操作是合法的,但是不安全。如果沒有在視圖上執行DML操作的必要,在建立時可以聲明只讀來避免對基表數據的非法修改。
語法:
CREATE [OR REPLACE] VIEW view_name[(alias[, alias…])] AS subquery [WITH READ ONLY]; |
案例:創建帶有READ ONLY約束的視圖
CREATE OR REPLACE VIEW vread_emp AS SELECT empno,ename,sal,deptno FROM emp WHERE deptno=10 WITH READ ONLY; |
對該表進行修改測試:
DELETE FROM vread_emp WHERE ename=‘CLARK‘; |
? 數據字典
和視圖相關的數據字典如下:
l USER_OBJECTS
l USER_VIEWS
l USER_UPDATABLE_COLUMNS
案例:USER_OBJECTS
SELECT object_name FROM user_objects WHERE object_type=‘VIEW‘; |
案例:USER_VIEWS
SELECT text FROM user_views WHERE view_name=‘V_EMP‘; --視圖名字要大寫 |
案例:USER_UPDATABLE_COLUMNS
SELECT column_name,insertable,updatable,deletable FROM user_updatable_columns WHERE table_name=‘V_EMP‘; |
? 創建復雜視圖
創建復雜視圖指在子查詢中包含了表達式、單行函數或分組函數的視圖。此時必須為子查詢中的表達式或函數定義別名。
如果不創建別名會有以下錯誤提示:
案例:創建一個視圖把emp表的數據按部門分組,獲得每個部門的平均薪水、薪水總和、最高薪水和最低薪水
CREATE VIEW vsalary_emp AS SELECT d.dname,AVG(e.sal) avg_sal,SUM(e.sal) sum_sal,MAX(e.sal) max_sal,MIN(sal) min_sal FROM emp e JOIN dept d ON e.deptno=d.deptno GROUP BY d.dname; |
SELECT * FROM vsalary_emp;
註意:復雜視圖不允許DML操作,否則會報錯。
當不再需要視圖的定義,可以使用DROP VIEW語句刪除視圖。
案例:刪除復雜VIEW
DROP VIEW vsalary_emp; |
2. 序列
? 序列的定義
序列(SEQUENCE)是一種用來生成唯一數字的數據庫對象。序列的值由Oracle程序按遞增或遞減順序自動生成,通常用來自動產生表的主鍵值,是一種高效率獲得唯一鍵值的途徑。
序列是獨立的數據庫對象,和表是獨立的對象,序列並不依附於表。
通常情況下,一個序列為一個表提供主鍵值,但一個序列也可以為多個表提供主鍵值。
? 創建序列
語法:
CREATE SEQUENCE [schema.] sequence_name [START WITH i] [INCREMENT BY j] [MAXVLUE m | NOMAXVALUE] [MINVALUE n | NOMINVALUE] [CYCLE | NOCYCLE] [CACHE p | NOCACHE] |
參數含義如下:
l sequence_name是序列名,將創建在schema方案下
l 序列的第一個序列值是i,步進是j
l 如果j是整數,表示遞增,j是負數,表示遞減
l 序列可生成的最大值是m,最小值是n
l 如果沒有設置任何可選參數,序列第一個值是1,步進是1
l CYCLE表示在遞增至最大值或遞減至最小值之後是否繼續生成序列號,默認是NOCYCLE
l CACHE用來指定先預取p個數據在緩存中,以提高序列值的生成效率,默認是20
案例:創建一個序列起始數據是100,步進是10
CREATE SEQUENCE emp_seq START WITH 100 INCREMENT BY 10; |
當創建序列後,必須先執行一次NEXTVAL,才能使用CURRVAL。
先不執行NEXTVAL,直接執行CURRVAL查看效果:
SELECT emp_seq.CURRVAL FROM dual; |
獲取第一個值並使用序列值為EMP插入新的數據:
INSERT INTO emp(empno,ename) VALUES (emp_seq.NEXTVAL,‘SEQ1‘); |
查詢新數據會發現插入的empno是100:
SELECT * FROM emp WHERE ename=‘SEQ1‘; |
運行一次NEXTVAL得到序列號加10,即110:
SELECT emp_seq.NEXTVAL FROM dual; |
查看當前序列號:
SELECT emp_seq.CURRVAL FROM dual; |
? 刪除序列
語法:
DROP SEQUENCE sequence_name; |
案例:刪除序列emp_seq
DROP SEQUENCE emp_seq; |
3. 索引
? 索引原理
索引是一種允許直接訪問數據表中某一數據行的樹形結構,為了提高查詢效率而引入,是獨立於表的對象,可以存放在與表不同的表空間(TABLESPACE)中。索引記錄中存有索引關鍵字和指向表中數據的指針(地址)。對索引進行I/O操作比對表進行操作要少很多。
索引一旦被建立就將被Oracle系統自動維護,查詢語句中不用指定使用哪個索引,是一種提高查詢效率的機制。
ROWID:偽列,唯一標識一條數據記錄,可理解為行地址。
? 創建索引
語法:
CREATE [UNIQUE] INDEX index_name ON table(column[,column…]) |
l index_name:表示索引名稱
l table:表示表名
l column:表示列名,可以簡歷單列索引和符合索引
l UNIQUE:表示唯一索引
案例:在emp表的ename列上建立索引
CREATE INDEX idx_emp_ename ON emp(ename); |
? 創建復合索引
復合索引也叫多列索引,是基於多個列的索引。
如果經常在ORDER BY子句中使用job和sal作為排序依據,可以建立復合索引,如下案例
案例:建立復合索引
CREATE INDEX idx_job_sal ON emp(job,sal); |
當做下面查詢時,會自動應用索引idx_job_sal
SELECT empno,ename,sal,job FROM emp ORDER BY job,sal;
? 創建基於函數的索引
如果需要在emp表的ename列上執行大小寫無關搜索,可以在此列上建立一個基於UPPER的函數的索引,如下案例:
CREATE INDEX emp_ename_upper_idx ON emp(UPPER(ename)); |
做以下查詢,會自動應用剛剛建立的索引:
SELECT * FROM emp WHERE UPPER(ename)=‘SMITH‘;
? 修改和刪除索引
如果經常在索引列上執行DML操作,需要定期重建所有,提高所有的空間利用率。
重建索引語法:
ALTER INDEX index_name REBUILD; |
案例:重建索引idx_emp_ename
ALTER INDEX idx_emp_ename REBUILD; |
當一個表上有不合理的索引,會導致操作性能下降,需要刪除。
刪除索引語法:
DROP INDEX index_name; |
案例:刪除idx_emp_ename
DROP INDEX idx_emp_ename; |
? 合理使用索引提升查詢效率
l 為經常出現在WHERE子句中的列創建索引
l 為經常出現在ORDER BY、DISTINCT後面的字段建立索引,如果建立的是復合索引,索引的字段順序要和這些關鍵字後面的字段順序一致
l 為經常作為表的連接條件的列上創建索引
l 不要在經常做DML操作的表上建立索引
l 不要在小表上建立索引
l 限制表上的索引數據,索引並不是越多越好
l 刪除很少被使用、不合理的索引
4. 約束
? 約束的作用
l 約束(CONSTRAINT),即約束條件,也稱作完整性約束條件
l 約束是在數據表上強制執行的一些數據校驗規則,當執行DML操作時,數據必須符合這些規則,如果不符合則無法執行
l 約束條件可以保證表中數據的完整性,保證數據間的商業邏輯
? 約束的類型
l 非空約束(Not Null),簡稱NN
l 唯一性約束(Unique),簡稱UK
l 主鍵約束(Primary Key),簡稱PK
l 外鍵約束(Foreign Key),簡稱FK
l 檢查約束(Check),簡稱CK
4.1 非空約束
? 建表時添加非空約束
非空約束用於確保字段值不為空,默認情況下,任何列都允許有空值,但業務邏輯可能會要求某些列不能取空值,當某個字段被設置了非空約束條件,這個字段中必須存在有效值。即:
u 當執行INSERT操作時,必須提供這個列的數據
u 當執行UPDATE操作時,不能給這個列的值設置為NULL
案例:建表時設置非空約束
CREATE TABLE test_emp( id NUMBER(8) NOT NULL, name VARCHAR2(30) NOT NULL, salary NUMBER(8,2) ); |
? 修改表時添加非空約束
可以在建表之後,通過修改表的定義,添加非空約束
案例:修改test_emp表salary列設置非空約束
ALTER TABLE test_emp MODIFY (salary NUMBER(8,2) NOT NULL); |
? 取消非空約束
取消某列的非空約束,可以采用重建表或修改表的方式。
案例:修改salary列取消非空約束
ALTER TABLE test_emp MODIFY (salary NUMBER(8,2) NULL); |
4.2 唯一性約束
? 唯一性約束
唯一性(Unique)約束條件用於保證字段或者字段的組合不出現重復值。當給表的某個列定義了唯一性約束條件,該列的值不允許重復,但允許是NULL值。唯一性約束條件可以在建表的時候建立,也可以在建表以後再建立。
? 添加唯一性約束
案例:建表時添加唯一性約束
CREATE TABLE emp2( eid NUMBER(6) UNIQUE, name VARCHAR2(30), email VARCHAR2(50), salary NUMBER(7,2), hiredate DATE, CONSTRAINT emp2_email_uk UNIQUE(email) ); |
案例:建表後增加唯一性約束條件
ALTER TABLE test_emp2 ADD CONSTRAINT test_emp2_name UNIQUE(name); |
如果在其它表上建立唯一性約束,則唯一性條件約束的名稱不能重復,不然會出現如下錯誤提示:
如:執行ALTER TABLE test_emp3 ADD CONSTRAINT test_emp2_name UNIQUE(name);
註意:如果一個已存在的表,有一列已經有重復字段,再想給這個表的這一列添加唯一性約束就會報錯,報錯內容為:有重復關鍵字。
4.3 主鍵約束
? 主鍵的意義
主鍵(Primary Key)約束條件從功能上看相當於非空(NOT NULL)且唯一(UNIQUE)的組合。主鍵字段可以是單字段或多字段組合,即:在主鍵約束下的單字段或者多字段組合上不允許有空值,也不允許有重復值。主鍵可以用來在表中唯一的確定一行數據,一個表上只允許建立一個主鍵,而其他約束條件則沒有明確的個數限制。
? 主鍵選取的原則
l 主鍵應是對系統無意義的數據
l 永遠也不要更新主鍵,讓主鍵除了唯一標識一行之外再無其他作用
l 主鍵不應包含動態變化的數據,如時間戳
l 主鍵應自動生成,不要人為幹預,以免使它帶有除了唯一標識一行以外的意義
l 主鍵盡量建立在單列上
? 添加主鍵約束
案例:建表時添加主鍵約束
CREATE TABLE test_emp3( id NUMBER(8) PRIMARY KEY, name VARCHAR2(30), salary NUMBER(8,2) ); |
案例:建表後添加主鍵約束
ALTER TABLE test_emp4 ADD CONSTRAINT test_emp3_pk PRIMARY KEY (id); |
4.4 外鍵約束
? 外鍵約束的意義
外鍵約束條件定義在兩個表的字段或一個表的兩個字段上,用於保證相關兩個字段的關系。如:
dept表:主表或父表
emp表:從表或子表
外鍵裏面的值,必須是NULL或者主鍵裏有的值。
主鍵裏想刪除一個值,必須是外鍵裏面沒有參照的(不存在的)。
? 添加外鍵約束
先建表,在建表後建立外鍵約束條件。
案例:
錯誤原因:因為dept1表沒有添加主鍵,刪除兩個表,重新配置外鍵約束,如下:
CREATE TABLE dept1( deptno NUMBER(8) PRIMARY KEY, loc VARCHAR2(30) ); CREATE TABLE emp1( id NUMBER(8), name VARCHAR2(30), deptno NUMBER(8) ); ALTER TABLE emp1 ADD CONSTRAINT emp1_deptno_fk FOREIGN KEY (deptno) REFERENCES dept1(deptno); |
? 外鍵約束對一致性的維護
l 從表上定義的外鍵的列值,必須從主表被參照的列值中選取,或者為NULL
l 當主表參照列的值被從表參照時,主表的該記錄不允許被刪除
案例:增加數據
INSERT INTO dept1 VALUES(10,‘NJ‘); --dept主表中添加deptno為10 INSERT INTO emp1 VALUES(1,‘smith‘,20); --emp從表中添加數據,deptno為20 |
報錯:違反完整約束條件
INSERT INTO emp1 VALUES(1,‘smith‘,10); --修改成10,添加成功 INSERT INTO emp1 VALUES(1,‘smith‘,NULL); --或者修改成NULL,添加成功 |
案例:刪除數據
DELETE FROM dept1 where deptno=10; --10這個值被從表參照,無法刪除 |
報錯:
DELETE FROM emp1 WHERE deptno=10; --必須先刪除從表中的參照值 DELETE FROM dept1 where deptno=10; --才可以刪除主表數據成功 |
? 外鍵約束對性能的降低
如果在一個頻繁DML操作的表上建立外鍵,每次DML操作都將導致數據庫自動對外鍵所關聯的對應表做檢查,產生開銷,如果已在程序中控制邏輯,這些判斷將增加額外負擔,可以省去。外鍵確定了主從表的先後生成關系,有時會影響業務邏輯。
? 關聯不一定需要外鍵約束
l 保證數據完整性可由程序或觸發器控制
l 簡化開發,維護數據時不用考慮外鍵約束
l 大量數據DML操作時不需考慮外鍵耗費時間
4.5 檢查約束
? 什麽是檢查約束
檢查(Check)約束條件用來強制在字段的每個值都要滿足Check中定義的條件,當定義了Check約束的列新增或修改數據時,數據必須符合Check約束中定義的條件。
? 添加檢查約束
ALTER TABLE emp1 ADD CONSTRAINT emp_id_ck CHECK(id<10); |
添加數據測試
INSERT INTO emp1 VALUES(11,‘jack‘,NULL); --報錯,違反檢查約束條件 |
添加正確數據:
INSERT INTO emp1 VALUES(8,‘jack‘,NULL); INSERT INTO emp1 VALUES(NULL,‘tom‘,NULL); --可以添加NULL值 |
註意:如果添加檢查約束的列已有數據並且與添加的CHECK條件不一致,則檢查約束添加會報錯。
視圖、序列、索引、約束