ORACLE SQL DAY08
- 創建一張表account_90,表結構與account一致,沒有數據
- account_90表中包含所有的90後客戶
- 通過演示理解什麼是視圖
- 每個客戶選擇了哪些資費標準
- 視圖的維護
- 視圖中的with check option約束
- 視圖中的with read only約束
- 創建唯一性索引
- 創建聯合索引
- 創建函數索引
- 序列號的應用場景和實現
1 創建一張表account_90,表結構與account一致,沒有數據
1.1 問題
創建一張與account表結構一樣的表account_90,表中不包含數據。
1.2 方案
在create table中可以嵌套SELECT語句,即子查詢。若子查詢的返回記錄數爲0,新建的表就只有結構。1 = 2是永假式,任何表都不會返回記錄。
- where 1 = 2
1.3 實現
代碼實現:
- create tableaccount_90
- as
- select * from account
- where 1 = 2 ;
2 account_90表中包含所有的90後客戶
2.1 問題
account_90表中包含所有的90後客戶。
2.2 方案
在insert中可以嵌套SELECT語句,即子查詢。出生日期是90後的客戶通過子查詢實現。
- select * from account
- whereto_char(birthdate,'yyyy') between 1990 and 1999;
2.3 實現
代碼實現:
- insert intoaccount_90
- select * from account
- whereto_char(birthdate,'yyyy') between 1990 and 1999;
2.4 擴展
3 通過演示理解什麼是視圖
3.1 問題
理解什麼是視圖,通過實驗證明之。
3.2 方案
表是數據庫對象,視圖是另一種。它們既有相似之處,也有很大區別。通過演示,幫助同學們理解什麼是視圖?
3.3 實現
創建一張表,插入記錄,提交。
- drop table testpurge;
- create tabletest(
- c1number,
- c2number);
- insert into testvalues (1,1);
- insert into testvalues (1,2);
- insert into testvalues (2,2);
- commit;
用DDL語句創建一張視圖,我們可以像操作表那樣操作視圖。
- create or replace viewtest_v1
- as
- select * from test
- wherec1 = 1;
- desctest_v1
- NameNull? Type
- ----------------------------------------- -------- --------
- C1 NUMBER
- C2 NUMBER
- select * fromtest_v1;
- C1 C2
- ---------- ----------
- 1 1
- 1 2
向視圖test_v1中插入一條記錄(1,3),查看test_v1和test中的變化
- insert intotest_v1values (1,3);
- select * fromtest_v1;
- C1 C2
- ---------- ----------
- 1 1
- 1 2
- 1 3
- select * fromtest;
- SQL> select * fromtest;
- C1 C2
- ---------- ----------
- 1 1
- 1 2
- 2 2
- 1 3
向表test中插入一條記錄(1,4),查看test_v1和test中的變化:
- insert into testvalues (1,4);
- select * fromtest_v1;
- C1 C2
- ---------- ----------
- 1 1
- 1 2
- 1 3
- 1 4
- select * fromtest;
- C1 C2
- ---------- ----------
- 1 1
- 1 2
- 2 2
- 1 3
- 1 4
向視圖test_v1中插入一條記錄(2,3),查看test_v1和test中的變化
- insert intotest_v1values (2,3);
- select * fromtest_v1;
- C1 C2
- ---------- ----------
- 1 1
- 1 2
- 1 3
- 1 4
- select * fromtest;
- C1 C2
- ---------- ----------
- 1 1
- 1 2
- 2 2
- 1 3
- 1 4
- 2 3
通過上述演示,我們發現視圖類似於windows中的快捷方式。結論:視圖就是一條SELECT語句,不佔用單獨的存儲空間,從視圖中查詢實際是執行視圖對應的SELECT語句。
- selectview_name,text fromuser_views
- whereview_name = 'TEST_V1';
- VIEW_NAME TEXT
- ---------- ---------------------------
- TEST_V1 select "C1","C2" from test
- wherec1 = 1
3.4 擴展
4 每個客戶選擇了哪些資費標準
4.1 問題
創建一張視圖,包含客戶名稱account表的real_name,unix服務器ip地址service表的unix_host, 資費編號cost表的id,資費信息描述cost表的descr。結果集中值包含開通了遠程登錄業務的客戶。
圖 - 1
4.2 方案
寫創建視圖語句的核心是寫SELECT語句,視圖中包含的列來自account表、service表、cost表,即三張表的連接操作。
- from account a join service s
- ona.id = s.account_id
- join cost c
- ons.cost_id = c.id;
每多一張表會多一個join on操作。
4.3 實現
代碼實現:
- create or replace viewaccount_cost_v
- as
- selecta.real_name,s.unix_host,c.id,c.descr
- from account a join service s
- ona.id = s.account_id
- join cost c
- ons.cost_id = c.id;
4.4 擴展
所有的客戶都在結果集中
圖 - 2
代碼實現如下:
- create or replace viewaccount_cost_v
- as
- selecta.real_name,s.unix_host,c.id,c.descr
- from account a left join service s
- ona.id = s.account_id
- left join cost c
- ons.cost_id = c.id;
- create or replace viewaccount_cost_v
- selecta.real_name,t.unix_host,t.descr
- from account a left join
- (selects.account_id,s.unix_host,c.descr
- from service s join cost c
- ons.cost_id = c.id) t
- ona.id = t.account_id
- create or replace viewaccount_cost_v
- as
- selecta.real_name,s.unix_host,c.id,c.descr
- from account a left join service s
- ona.id = s.account_id
- left join cost c
- ons.cost_id = c.id;
- create or replace viewaccount_cost_v
- as
- selectreal_name,c.name
- from (select *
- from account a left join service s
- ona.id=s.account_id) aa left join cost c
- onaa.cost_id =c.id
5 視圖的維護
5.1 問題
若將源表刪除,基於源表的視圖會發生怎樣的變化?
5.2 方案
視圖是一個依賴表的數據庫對象,查詢視圖最終都要通過查詢源表實現。如果源表的結構發生變化,對視圖的操作就有可能出問題。查看視圖的狀態是幫助我們發現視圖是否可用的方法。
5.3 實現
代碼實現如下:
視圖test_v1基於表test,此時它的狀態爲valid:
- selectview_name,text fromuser_views
- whereview_name = 'TEST_V1';
- VIEW_NAME TEXT
- ---------- ---------------------------
- TEST_V1 select "C1","C2" from test
- wherec1 = 1
- columnobject_name format a15
- columnobject_type format a10
- selectobject_name,object_type,status fromuser_objects
- whereobject_name = 'TEST_V1';
- OBJECT_NAMEOBJECT_TYP STATUS
- --------------- ---------- ------
- TEST_V1 VIEW VALID
將test表刪除,檢查視圖test_v1的狀態:
- drop table testpurge;
- desctest_v1
- ERROR:
- ORA-24372: invalid object for describe
- 提示:視圖test_v1是無效的數據庫對象
- select * fromtest_v1;
- ERROR at line 1:
- ORA-04063: view "JSD1302.TEST_V1" has errors
- 提示:視圖test_v1有錯誤
- selectobject_name,object_type,status fromuser_objects
- whereobject_name = 'TEST_V1';
- OBJECT_NAMEOBJECT_TYP STATUS
- --------------- ---------- -------
- TEST_V1 VIEW INVALID
- 提示:test_v1的狀態轉變爲無效INVALID。
- alter viewtest_v1compile;
- Warning: View altered with compilationerrors.
- 提示:在不做任何修改的情況下,重新編譯視圖仍舊出錯。
- column text format a40
- column name format a10
- set linesize 200
- select * fromuser_errors;
- NAME TYPE SEQUENCE LINE POSITION TEXT ATTRIBUTEMESSAGE_NUMBER
- ------- ------ -- -- -- ------------------------------------- ----- -
- TEST_V1 VIEW 1 0 0 ORA-00942:table or view does not exist ERROR 0
- 提示:編譯出錯的原因是test表不存在。
- 創建test表以解決表不存在問題。
- create tabletest(c1number,c2number);
- selectobject_name,object_type,status fromuser_objects
- whereobject_name = 'TEST_V1';
- OBJECT_NAMEOBJECT_TYP STATUS
- --------------- ---------- -------
- TEST_V1 VIEW INVALID
- select * fromtest_v1;
- no rows selected
- OBJECT_NAMEOBJECT_TYP STATUS
- --------------- ---------- -------
- TEST_V1 VIEW VALID
- 原因:當drop源表,所有依賴源表的視圖都將變爲invalid。即視圖本身存在,因爲源表的丟失已經不能對視圖正常操作了;當重新定義源表後,再次查詢視圖,系統先會對其編譯:alterview_namecompile;若編譯成功,可以正常操作視圖。
- 結論:對源表進行DDL操作後,需要檢查數據庫對象的狀態是否有invalid,若有,需要改正。
5.4 擴展
6 視圖中的with check option約束
6.1 問題
通過視圖test_v1可以插入(2,3),但從視圖中不能查詢到該記錄,這樣的情況不符合邏輯,怎樣避免?
6.2 方案
可以對視圖定義約束,with check option約束就是用來解決能對視圖進行DML操作卻不能SELECT的問題。
- whereos_usernamelike 'h%'
6.3 實現
在創建視圖時增加with check option約束,該約束要求通過視圖插入的記錄必須符合where條件。
- create or replace viewtest_ck
- as
- select * from test
- wherec1 = 1 with checkoption;
- insert intotest_ckvalues (2,3);
- ERROR at line 1:
- ORA-01402: view WITH CHECK OPTIONwhere-clause violation
6.4 擴展
7 視圖中的with read only約束
7.1 問題
對於簡單視圖來說,如何實現不允許DML操作?
7.2 方案
在創建視圖時增加with read only約束,該約束能夠實現只讀。
7.3 實現
在創建視圖時增加with read only約束,該約束要求對視圖只能查詢,不能做DML操作。
- create or replace viewtest_ro
- as
- select * from test
- wherec1 = 1 with readonly;
- insert intotest_rovalues (1,5);
- ERROR at line 1:
- ORA-01733: virtual column not allowed here
7.4 擴展
8 創建唯一性索引
8.1 問題
爲表中的列創建唯一性索引。
8.2 方案
oracle提供了一種索引形式是唯一性索引,語法是:
- create unique index indname
- ontabname (colname);
要求該列的取值必須唯一。
8.3 實現
代碼實現:
- create tabletest(
- c1 number constrainttest_c1_pk primarykey);
- insert into testvalues (1);
- insert into testvalues (1);
- ERROR at line 1:
- ORA-00001: uniqueconstraint (JSD1302.TEST_C1_PK) violated
- 第二條insert語句違反了唯一性約束
- alter table test drop primarykey;
- create unique indextest_c1_uniidx
- ontest(c1);
- insert into testvalues (1);
- insert into testvalues (1);
- ERROR at line 1:
- ORA-00001: uniqueconstraint (JSD1302.TEST_C1_UNIIDX) violated
- 注意:唯一性約束的名字是唯一性索引的名字
- 結論:唯一性約束是通過唯一性索引實現的,二者是等價的。
8.4 擴展
9 創建聯合索引
9.1 問題
爲表中的多列創建索引。
9.2 方案
oracle提供了一種索引形式是多列索引,在on關鍵字後的()裏可以跟多列。如果有兩列經常在一起查詢,適合建多列索引。
9.3 實現
代碼實現
- create tabletest(
- c1 number constrainttest_c1_pk primarykey,
- c2number,
- c3number);
- create indextest_c2_c3_idx
- ontest(c2,c3);
9.4 擴展
10 創建函數索引
10.1 問題
oracle爲什麼提供函數索引?怎樣創建函數索引?
10.2 方案
若在c2列上創建普通索引,where round(c2) = 10是用不了該索引的,oracle仍然會用全表掃描的方式查詢數據,要想提高查詢效率,必須使用函數索引。
- ontabname (funame(colname,..))
10.3 實現
代碼實現
- create tabletest(
- c1 number constrainttest_c1_pk primarykey,
- c2number,
- c3number);
- create indextest_c2_funidx
- ontest(round(c2));
10.4 擴展
11 序列號的應用場景和實現
11.1 問題
oracle爲什麼提供sequence?怎樣創建sequence?
11.2 方案
表中的PK/UK列要求取值一定要唯一,在程序執行尤其是併發執行時,怎樣保證每次插入的值是唯一的。oracle提供了自己的解決方案:使用sequence。
- create sequenceseq_name
- [increment by 1|integer]
- [start withinteger]
- [maxvalueinteger|nomaxvalue]
- [minvalueinteger|nominvalue]
- [cycle|nocycle]
- [cache 20|integer|nocache]
11.3 實現
代碼實現
- drop table testpurge;
- create tabletest(
- c1 number constrainttest_c1_pk primarykey);
- drop sequences_test_c1;
- create sequences_test_c1
- start with 1302001;
- insert into testvalues (s_test_c1.nextval);
- insert into testvalues (s_test_c1.nextval);
- commit;
- insert into testvalues (s_test_c1.nextval);
- rollback;
- insert into testvalues (s_test_c1.nextval);
- select * fromtest;
- C1
- ----------
- 1302001
- 1302002
- 1302004
- selects_test_c1.currval fromdual;
- CURRVAL
- ----------
- 1302004
- selectsequence_name,cache_size,last_number
- fromuser_sequences;
- SEQUENCE_NAMECACHE_SIZELAST_NUMBER
- ------------------------------ ---------- -----------
- S_TEST_C1 20 1302021