SlideShare a Scribd company logo
1 of 71
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
第八章 表格
前言
Relational Database 一般翻譯為關連式資料庫,但這個中文翻譯常造成誤解,認為此種資料庫的表格
(Table)與表格之間一定存有某種關連(Relationship),因此才被稱作關連式資料庫。其實並不是如此,這
裡所說的關連(Relation)是 E.F.Codd 所用來當作儲存資料的結構,由於此種資料庫是由許多關連所組成,
所以才稱做關連式資料庫。本章節的重點便是介紹表格(Table),是資料庫用來儲存資料的結構,就是關
連式資料庫所謂的關連。
8.1 表格相關事項
在前面的章節中曾經提到,Oracle Database 在邏輯結構中,是由表格空間(Tablespace)所組成,表格空
間是由區段(Segment)所構成,區段為多個擴充區塊(Extent)的集合,而每個擴充區塊則為連續的資料區
塊(Data Block)所組成的。表格只是眾多區段的其中一種,然而卻是最重要的一種,因為所有的資料都存
放在表格中,無論是資料辭典(Data Dictionary)還是一般使用者的資料。
當一個表格初始建立時,其相關的定義如表格名稱、欄位名字、欄位型態以及限制條件等資訊是存放在資
料辭典中,而此表格的資料則需要儲存在額外空間。所謂的額外空間就是資料區塊,然而依 Oracle 資料
庫的規定,儲存空間的配置是以擴充區段為單位。所以一個表格建立之初,至少要配置一個擴充區塊以供
該表格儲存資料使用,區段則是屬於同一個表格的擴充區塊集合。不過當表格持續地被新增(Insert)、修
改(Update)、刪除(Delete)資料後,之前已配置的擴充區塊可能已經不敷使用,所以 Oracle 資料庫會自動
配置一個新的擴充區塊給該表格,直到該表格所能擁有的最大擴充區塊個數為止。
8.1.1 區塊的結構
資料區塊的結構可以分成三大部分:快取層(Cache Layer)、交易層(Transaction Layer)與資料層(Data
Layer) 。根據不同的物件,其資料區塊的結構有著些許的不同,此處以表格區塊為範例。
	
快取層(Cache Layer)
快取層中存放著此區塊位置(Data Block Address)、區塊型態(Block Type:TABLE/INDEX、UNDO、
TEMPORARY)、區塊格式(Block Format:v7/v8),系統改變號碼(System Change Number-縮寫為
SCN)以及區塊尾端(Tail:存放此區塊中最後 4 個 Bytes 資料,用來與區塊註腳(Block Footer)的內容比
對,檢查區塊內容是否正確)。此區域固定佔 20 Bytes 的空間。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
交易層(Transaction Layer)
交易層分為固定的交易層(Fixed Transaction Layer)與變動的交易層(Variable Transaction Layer)。固
定的交易層顧名思義的表示此層的大小是固定,不因為任何因素而改變其大小。而變動的交易層的大小則
因為有關係的交易列表(Interested Transaction List-縮寫為 ITL)的個數,而有不同的大小。不過變動的
交易層一但佔用空間後,之後即便同時對此資料區塊異動的交易數量減少,也不會減少 ITL 的數量,也就
是變動的交易層的空間只有可能增加,而不會減少。
固定的交易層:此區域放著資料區塊的型態(Block Type)、最後一次資料區塊進行清理(Block CleanOut)
的時間、 有幾個 ITL 在變動的交易層中。此外如果是可用區塊列表(Freelists)管理的表格區塊,則還有可
用區塊列表鏈結(FreeList Link)與可用空間的鎖定(FreeSpace Lock)。如果是自動區段空間管理
(Automatic Segment Space Management-縮寫為 ASSM)管理的表格區塊,則存放的是層級 1 的位元組
區塊(L1 Bitmap Block)的位置、區塊位置的範圍(DBA Range)與操作碼(OP Code),以及區塊的版本資
訊(Block Incarnation)。此區域固定佔 48 Bytes 的空間。
變動的交易層:這個區域用來放 Interested Transaction List(ITL),有時被稱做交易項目(Transaction
Entry),每個 ITL 佔 24 Bytes 空間。當建立表格時,可以使用 INITRANS 指定初始的 ITL 個數,預設值
為 1。MAXTRANS 在 10g 之後自動設為 255,表示最多可有 255 個 ITL 存在。當每個交易
(Transaction)想要進行異動區塊內容,不論是新增、異動、刪除資料列時,首先必須找到可用的 ITL,將
交易相關的資訊填入 ITL 中,之後才可以進行後續的操作。不過已用過的 ITL 可以重複被使用,但已產
生的 ITL 個數將不會減少,所以 Oracle 伺服器會儘可能地重複使用那些已存在的 ITL。若找不到可用的
ITL,還是會新增一個 ITL,ITL 個數可多達 255。
一般所稱的資料區塊標頭(Block Header)是指快取層與交易層。
資料層(Data Layer)
表格目錄(Table Directory)
此結構的主要用途為當表格為叢集表格(Cluster Table:叢集表格由一個或多個表格組成),同一個叢集表
格的資料區塊中可能有著屬於不同表格的資料列(Row)。因此必須使用表格目錄的內容來找到屬於特定表
格的資料列。不過如果表格是非叢集型態,表格目錄中只有一個表格索引(Table Index)即可。但是叢集表
格則根據此叢集表格由幾個表格組成,決定需要幾個表格索引。而每個表格索引需要 4 Bytes 空間。
資料列目錄(Row Directory)
在這個表格中的每一筆資料列(Row)都有一個記錄在資料列目錄(Row Directory)中。因為存放在資料列
資料區域中的每個資料列之間,並沒有特別的間隔符號,所以每次想要讀取某個資料列時,需要提供該資
料列的資料列辨識碼(Row ID),其中的資料列號碼(Row Number)就是指定讀取資料列目錄的哪一筆記錄。
而該筆記錄的內容則記載著某筆資料列的資料列標頭的位置,利用資料列目錄的內容便可以由資料區塊找
出所要的資料列。
當一筆資料列被新增到此區塊時,須先找到可用的資料列目錄結構,如果沒有任何現有的結構可供使用,
則會增加一個資料列目錄結構,用來存放該筆資料列的資料列標頭在資料層(Data Layer)的位置,每個資
料列目錄結構需要 2 Bytes 的空間。然而若此區塊中的資料列被刪除後,則該筆資料列所使用的資料列目
錄結構則可以被重複被之後新增的資料列使用,不過資料列目錄所佔的空間不會縮小,即使有一大堆空的
資料列目錄結構存在。
所謂的區塊負擔(Block Overhead)是由區塊標頭(Block Header)、表格目錄(Table Directory)及資料列目
錄(Row Directory)組成。
可用空間(Free Space)
整個資料區塊空間扣除區塊負擔與資料列所佔用空間後,所剩餘的空間稱做可用空間(Free Space)。可用
空間可供新增資料列或因異動資料列(異動後的資料列長度較異動前來的大)使用。同時可用空間也可供區
塊負擔因 ITL 個數增加或資料列目錄結構增加而需要的空間。在這樣的兩面夾擊之下,可用空間將會逐漸
地減少。不過當有些資料列因為刪除或異動而導致資料列資料所佔空間減少時,可用空間將因此而增加。
然而需要注意的是,區塊負擔已經使用的空間,將不會因為任何原因而減少。
資料列資料(Row Data)
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
由眾多的資料列片段(Row Piece)組成,也就是我們一般認知的資料列。資料列片段本身也是由資料列標
頭(Row Header)與欄位資料(Column Data)組成。
資料列標頭(Row Header)為資料列旗標(Row Flag)、鎖定位元組(Lock Byte)、欄位數量(Number Of
Columns)、叢集索引(Cluster Index)、鏈結資訊(Chaining Information)所組成。
資料列旗標(Row Flag):用來儲存此筆資料列的狀態,是否為單一資料列片段組成或者為鏈結資料列片段
(Chaining Row Piece)的第一個片段還是最後一個片段,也可以顯示這筆資料列已經被刪除等訊息。資料
列旗標需要佔用 1 Byte 空間。
鎖定位元組(Lock Byte):記錄此筆資料列是否被某個交易鎖定,若該資料列正被某個交易鎖定,則鎖定
位元組中將會儲存某個區塊負擔的 ITL 位置,而該 ITL 中有鎖定該資料列的交易的交易辨識碼
(Transaction ID)。交易辨識碼由還原區段號碼(Undo Segment Number)、槽號碼(Slot Number)與順序
號碼(Sequence Number)組成。鎖定位元組需要 1 Byte 的空間。
欄位個數(Number Of Columns):用來記錄該資料列的欄位資料(Column Data)中有存在幾個存放欄位長
度(Column Length)的結構。欄位個數佔用 1 Byte 的空間。
叢集鍵值索引(Cluster Key Index):只有當此區塊為叢集表格的資料區塊時,才需要這個結構標示資料列
為哪個叢集表格的成員(Cluster Table Member)。叢集鍵值索引需要 1 Byte 的空間。
連結資訊(Chaining Information):當發生資料列遷移(Row Migration)或資料列鏈結(Row Chaining)時,
需要在資料列標頭中記錄另外的資料列片段的位置。鏈結資訊需要 6 Bytes 的空間,其中包含資料列片段
所在的區塊位置(Data Block Address)及該區塊標頭的資料列目錄位置(Row Number)。
如果此表格不是叢集表格,同時也沒有發生資料列遷移或資料列鏈結的情況,則資料列標頭等於資料列
負擔,只需要 3 Bytes 的空間(Row Flag/Lock Byte/# Of Cols)即可。
欄位資料(Column Data)為真正欄位值儲存的地方,但是每個欄位值需要使用一組欄位長度(Column
Length)及欄位值(Column Value)來儲存。因為欄位與欄位之間沒有任何間隔符號,所以使用欄位長度來
說明該欄位值所佔的空間為多少。假設某個欄位長度的值為 10,表示欄位長度後的 10 Bytes 所儲存的
內容,為該欄位的值,也就是說該欄位值佔 10 Bytes 的空間。當欄位值(Column Value)所佔的空間在
250 Bytes 以下時,則相對應的欄位長度只需要 1 Byte 即可。若當欄位值(Column Value)所佔的空間超
過 250 Bytes 以上時,則欄位長度需要 3 Bytes 的空間。欄位值(Column Value)為空值(Null)時,則該欄
位的欄位長度的內容值將為 0,表示不需要欄位值(Column Value)。但若該空值的欄位為於資料列片段的
最後面,則連欄位長度都不需要儲存,以節省空間。
SQL> CREATE TABLE frank.test (a NUMBER,b NUMBER,c NUMBER);
SQL> SELECT * FROM frank.test;
A B C
----------- ------------ ----------
a 1 /*B欄位值為NULL*/
b /*B,C欄位值皆為NULL*/
--以下為表格frank.test的block dump
tab 0, row 0, @0x1f97
tl: 9 fb: --H-FL-- lb: 0x1 cc: 3 /*fb為Flag Byte即Row Flag。cc為Number Of Columns */
col 0: [ 1] 61 /*[1]為Column Length,表示後面1 Byte為Column Value也就是61*/
col 1: *NULL* /*空值僅需要Column Length即可*/
col 2: [ 2] c1 02 /*[2]為Column Length,表示後面2 Byte為Column Value也就是c1 02*/
tab 0, row 1, @0x1f92
tl: 5 fb: --H-FL-- lb: 0x1 cc: 1 /*cc為1,表示此row piece中只存放1個欄位的值,因為B,C皆為空值*/
col 0: [ 1] 62
區塊尾部(Tail)
存放此資料區塊的最後 4 個 Bytes 資料,用來與儲存在快取層(Cache Layer)的區塊尾端資料比對,檢查
兩者是否一致。若兩者不一致,則會出現 ORA-01578 區塊毀損的錯誤訊息。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
8.1.2 資料列與區塊的關係
當一個表格被建立之後,至少會配置一個擴充區段。所以目前這個表格所有的列將會存放在擴充區塊中,
但因為擴充區塊為連續的資料區塊組成,所以列實際是存放在資料區塊中。表格是資料列(Row)的集合,
列是欄位(Column)所構成的,欄位是由欄位名字與資料型態組成。
資料列鏈結(Row Chaining)
由於 Oracle 資料庫進行 I/O 的最小單位是一個資料區塊,所以通常建議一筆資料列應該要小於該表格的
資料區塊大小,這樣在讀取一筆資料列時,只需要讀 1 個資料區塊即可,這樣可以減少 I/O 成本。但是
建立表格時,不能指定此表格所使用的資料區塊大小。因為資料區塊的大小是在建立表格空間時所設定,
所以在建立表格之前時,需要慎重地選擇所使用的表格空間。因為當新增(Insert)操作將資料列新增到表
格時,如果如果資料列的大小大於表格所使用的資料區塊大小,這時該資料列將被切割為數個資料列片段
(Row Piece),然後將資料列片段分別存放在不同的資料區塊。而這些資料列片段透過資料列表頭(Row
Header)中的鏈結資料(Chaining Information)鏈結在一起,每個資料列片段的鏈結資料記錄著下一段的資
料列片段位置。所以當 Oracle 資料庫存取該資料行時,需要讀取多個資料區塊,才能將這筆資料列讀到
緩衝區快取(Buffer Cache)。因此整體的效能便受到拖累(因為 I/O 的數量增加)。
	
這種情況稱作資料列鏈接(Row Chaining),通常發生在新增操作居多,有時一些異動操作也會造成。發
生的原因可能是資料列太大或資料區塊太小,資料庫管理者可以透過正規化將資料列變小或將表格移動到
較大區塊的表格空間來解決資料列鏈結的問題。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
	
	
資料列遷移(Row Migration)
當一個資料區塊中已經存在的資料列,因為更新操作(Update)造成原本資料列變大。如果現在資料列所處
區塊的可用空間(Free Space)夠大,這筆資料列會依然位於現在的資料區塊中。但是若可用空間不夠大,
則 Oracle 資料庫會尋找另一個可用空間夠大的區塊(同一個區段),將整筆資料列都遷移到該區塊。但是因
為索引(Index)中已經將原來資料列的位置當成索引項(Index Entry)的一部份,所以資料庫在原本的資料
區塊中,將繼續保存原來的資料列標頭(Row Header),並將其中的鏈結資料(Chaining Info)填入新資料
列的位置,因此當 Oracle 資料庫透過索引存取該筆資料列時,會先讀取到建立索引當時,該資料列所在
的區塊,但是現在該資料列已經遷移到另一個資料區塊中,Oracle 資料庫只好再利用舊列表頭的鏈結資
料存取現在資料列的區塊,因此至少需要讀取兩個表格的資料區塊才能夠取得一筆資料列。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
	
這種情況稱做資料列遷移,並可以透過保留較大的可用空間解決,即增加表格的 PCTFREE 參數值。
PCTFREE 參數預設為 10,表示當一個資料區塊的可用空間佔資料區塊的比率(free space/block size)低
於 10%時,該資料區塊將被設定為滿區塊(Full Block),表示該資料區塊不能再被新增資料列,但是可以
被更新或刪除資料列。而所保留的可用空間便是提供空間給未來更新資料列時,可以用來容納更新後的資
料列。
若已經發生資料列遷移,則可以使用表格重組(Table Reorganization)來消弭資料列遷移的情況。因為表
格重組的操作,都是使用新增(Insert)的方法,而資料列遷移則是由更新(Update)所產生。所以經過表格
重組後,便可以消弭資料列遷移的問題。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
	
8.1.3 正規化(Normalization)
在資料庫設計的相關技巧中,正規化是管理人員耳熟能詳的基本技巧,而基本的正規化至少要達到第三正
規化,才有正規化的效果。正規化可以帶來以下的一些好處:1.避免資料重複。2.節省儲存空間。當然某
些情況下,正規化可能導致效能上的問題。這時可以適時地使用反正規化來增加整體的效能,不過在進行
反正規化之前,當然還是要先正規化,因為不是每個表格都需要反正規化。
第一正規化 (First Normal Form:1NF)
定義:每個表格中都要有主鍵(Primary Key)用以辨識資料列,而且表格中不能有重複的欄位,同時每個
欄位只能儲存一筆值。
說明:這個表格中學號可以用來當做 Primary Key,因為每個學生都有一個不重複的學號。但是各科成績
這個欄位內,儲存國文、英文、數學的資料,便違反第一正規化的每個欄位只能有一個值的限制。因此必
須將各科成績的欄位執分別存放到不同的欄位,例如:國文、英文、數學。現在這個表格已經符合第一正
規化的要求。
	
第二正規化(Second Normal Form:2NF)
定義:首先必定要滿足第一正規化的要求,而且表格中非主鍵的欄位,還必須跟主鍵有完全相依性。
說明:國文、數學、英文、總分都與學號有著完全的相依性。所以此表格也滿足第二正規化的要求。
額外說明︰假設某表格由學號、科目、成績、教室所組成。因為同一位學生有多個科目的成績,所以主鍵
學號與科目組成。同時每個欄位只有單一值,所以這個表格符合第一正規化。但是非主鍵欄位:上課教室,
只與主鍵中的科目相關,不與學號相關。這種情況稱作部份相依。而成績則與主鍵完全相依,因為每個成
學號 各科成績(國文,英文,數學) 總分
100 90,85,95 270
101 85,80,100 265
學號 國文 英文 數學 總分
100 90 85 95 270
101 85 80 100 265
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
績都是以特定學號與特定科目為分別。因此為符合第二正規化的要求,需要將上課教室移出本表格,另外
建立一個表格由科目與上課教室組成,這樣才會符合第二正規化的要求。
科目 上課教室
國文 A
英文 B
數學 A
第三正規化(Third Normal Form:3NF)
定義:當滿足第二正規化後,非主鍵欄位之間不能存在相依性。
說明:因為總分為國文、英文、數學等欄位的加總,所以這些非主鍵欄位之間有相依性。所以必須將總分
欄位由表格中移除,另外建立一個表格由學號與總分組成
如此便可以滿足第三正規化的要求。
學號 總分
100 270
101 265
	
正規化所造成的問題
如果不建立總分表格:
由 AP 人員必須將計算公式(國文+數學+英文)寫到程式中,這種方法的好處是,表格依然維持正規的設計,
但是若計算公式一但有所變動,則需要修改程式內容,以及必須將新的程式部署到各個客戶端。
學號 科目 成績 上課教室
100 國文 90 A
100 英文 85 B
100 數學 95 A
101 國文 85 A
101 英文 80 B
101 數學 100 A
學號 科目 成績
100 國文 90
100 英文 85
100 數學 95
101 國文 85
101 英文 80
101 數學 100
學號 國文 英文 數學 總分
100 90 85 95 270
101 85 80 100 265
學號 國文 英文 數學
100 90 85 95
101 85 80 100
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
建立一個視觀圖(VIEW),將計算公式產生總分的虛擬欄位(CREATE VIEW student_view AS SELECT
國文,數學,英文,(國文+數學+英文) as 總分 FROM student),這樣便可以透過視觀圖得到總分的資料。
這種方式的缺點是必須多花一些維護成本在視觀圖的管理上。
解決方案:自 Oracle Database11g 後可以採用虛擬欄位,解決此種問題。若使用反正規化的技巧解決此
問題。
如果建立總分表格:
必須使用結合(Join)指令才能得到各科成績與總分的結果,可能導致大量的結合指令發生,進而影響效能。
解決方案:可以使用叢集(Cluster)表格將兩個表格叢集起來,讓操作結合指令時,可以減少資料區塊的
I/O 量。也可以使用反正規化的技巧解決此問題。
反正規化
資料庫管理者也可以在 Student 表格上,多加一個總分的欄位,其內容值為國文、數學、英文的總和。
並利用觸發器(Trigger)或前端應用程式在相關分數(國文、數學、英文)變動時,自動維護總分的內容,以
保持資料的一致性。此方式即所謂的反正規化,可以增加查詢的效能,但也造成儲存空間的浪費,同時增
加了資料不一致的風險。所以使用反正規化前,必須仔細設計,避免相關的問題發生。
8.2 基本的資料型態
雖然 Oracle 資料庫支援許多種資料型態,但是正如”80-20”法則所發現的現象,絕大多數的表格中,
常用到的資料型態不脫文字、數字、日期等基本型態。以下便針對這些資料型態進行說明。
8.2.1 文字型態
此型態的欄位用來儲存文字資料,但是建立此種欄位前,需要注意資料寬度與編碼的選擇。
寬度
文字資料型態還可以依儲存空間分成:固定寬度(CHAR/NCAHR)與變動寬度
(VARCHAR2/NVARCHAR2/LONG/CLOB)兩種。
所謂固定寬度是說雖然輸入的欄位值小於該欄位的限制長度,但是實際儲存資料時,會先自動向右補足空
白後,才將欄位值的內容儲存到資料區塊中。這種方式較浪費空間,但是存取效率較變動寬度來得好,同
時也可以減少資料列遷移的發生。CHAR(x Byte|Char)表示此欄位最大只能存放 x Bytes(預設)或 x
Characters 以資料庫字符集編碼的資料。Byte 表示 x 的單位是 Byte,Char 表示 x 的單位為 Character。
當一個 Character(符號)需要多個 Bytes 才能編碼時,CHAR(1 Byte)與 CHAR(1 Char)的實際儲存空間便
不相同,CHAR(1 Byte)只能容納 1 個 Byte 的資料,而 CHAR(1 Char)則可以容納 1 個 Character 的資
料,跟據 Character 由幾個 Bytes 所編碼決定,實際可以容納多少 Bytes(1/2/3/4)的資料。CHAR 的資
料欄位最大能夠存放 2000 Bytes 的資料。NCHAR 也是 2000 Bytes 的限制,不過 NCHAR(10)只有一
種選擇,即 10 CHAR,不能使用 10 Byte 的方式。
變動寬度則是當輸入的欄位值小於該欄位的限制長度,直接使用欄位值的內容儲存到資料區塊中,不會補
上空白,可以節省資料區塊的空間。VARCHAR2(x Byte|Char) 表示此欄位最大只能存放 x Bytes(預設)
或 x Characters 以資料庫字符集編碼的資料。Byte 表示 x 的單位是 Byte,Char 表示 x 的單位為
Character。當一個 Character(符號)需要 n 個 Bytes 才能編碼時,CHAR(1 Byte)與 CHAR(1 Char)的實
際儲存空間便不相同,CHAR(1 Byte)只能容納 1 個 Byte 的資料,而 CHAR(1 Char)則可以容納 1 個
Character 的資料,跟據 Character 由幾個 Bytes 所編碼決定,實際可以容納多少 Bytes(1/2/3/4)的資
料。 VARCHAR2 的資料欄位最大能夠存放 4000 Bytes 的資料。NVARCHAR2 也是 4000 Bytes,不
過 NVARCHAR2(10)只有一種選擇,即 10 CHAR,不能使用 10 Byte 的方式。而 LONG 可以儲存到
2G bytes 的資料。
編碼
文字型態的資料型態可依編碼方式分成:資料庫字符集(CHAR/VARCHAR2/CLOB/LONG)與國際字符
集(NCHAR/NVARCHAR2/NCLOB)兩種。資料庫中的文字資料都是透過字符集將符號轉換成數字後,才
存放到資料區塊中。透過不同的編碼集轉換,即便是相同的符號,也可能轉換成不同的數字。當然如果使
用錯誤的字符集,便可能無法正確地將資料區塊中的數字轉換為原本的符號。字符集的相關說明請參考
4.2.3。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
CHAR/VARCHAR2/LONG/CLOB 都用來儲存文字資料,所使用的編碼為資料庫字元集(Database
Character Set),在建立資料庫時所指定的。通常不能再更改,不過在特殊情況下,可以更改。
從 Oracle8i 開始,新增以下三種資料型態:NCHAR/NVARCHAR2/NCLOB,也可以用來存放文字資料,
不過所使用的編碼方法為本國字元集(National Character Set)。自 Oracle9i 後只能由 Unicode 中的
UTF8(變動寬度)或 AL16UTF16(固定寬度)則一為之。
8.2.2 數字型態
數字型態欄位用來儲存數字資料,不過根據不同的數字資料,可以分成下列幾種型態。
NUMBER
NUMBER(P,S)是最常見的數字型態,可存放的資料從 10^
-130
到 10^
126
(不包含此數值),需要 1 到 22
Bytes 不等的儲存空間。
P 是 Precision(精確度)的縮寫,表示最多位數的有效十進位位數(digit),最多不能超過 38 個有效位數。
最大有效數位(Most Significant Digit)是數值的最左邊的非零位數,最低有效數字(Least Significant
Digit)為數值的最右邊的位數。因此 123.45 這個數值中,1 是 MSD 而則是 LSD。
S 是 Scale 的縮寫,可使用範圍為-84 到 127。
Scale 為正數,表示從小數點到最低有效數字的位數。
Scale 為負數時,表示從最大有效數字到小數點的位數,但不包括最大有效數字。同時表示自小數點左邊
S 位數上四捨五入。
當 Scale 值大於 Precision 時,表示由小數點後的第 S 位數向左,不能有超過 P 個位數。同時自小數點後
的第 S 位開始四捨五入。
範例︰
原始資料 資料型態 儲存結果
123.45 NUMBER
其實是宣告為 float 浮點數,P 為 38
123.45
123.45 NUMBER(3)
等同於 NUMBER(3,0)
123(小數點後四捨五入)
總精確度為 3 位,無小數點後位
數。
123.45 NUMBER(3,2) 無法儲存(3 表示最大精確度為 3 個
digit,且小數點後的 digit 佔 2 個),
原始資料共有 5 個 digit。
123.45 NUMBER(5,2) 123.45
123.45 NUMBER(6,2) 123.45
123.45 NUMBER(5,-1) 120(在小數點左邊的 1 位,進行四
捨五入,因為 3 不足 5,則捨去)
0.02345 NUMBER(4,5) 0.02345(小數點後第 5 位向左不能
有超過 4 個數字)
0.023456 NUMBER(4,5) 0.02346(小數點後第 5 位向左不能
有超過 4 個數字,並從小數點後第 5
位開始四捨五入,所以 56 進位成 6)
0.12345 NUMBER(4,5) 無法儲存(小數點後第 5 位向左不能
有超過 4 個數字,但 12345 共 5 個
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
數字)
INTEGER
INTEGER 是 NUMBER 的子型態(SubType),其實等同 NUMBER(38,0),可以用來儲存整數,若數值有
小數,則會被四捨五入。如果需要限制數值的精確度,則建議使用 NUMBER(P,0),因為 INTEGER 的精
確度固定為 38。
--為方便觀察結果,往後的範例皆使用sys身份進行操作
SQL> CONNECT / AS SYSDBA
SQL> CREATE TABLE frank.t1_int (a INTEGER);
SQL> DESC frank.t1_int
Name Null? Type
----------------------------------------------------------------- -------- ----------------------------------------
A NUMBER(38)
SQL> CREATE TABLE frank.t2_int (a INTEGER);
SQL> DESC frank.t2_int
Name Null? Type
----------------------------------------------------------------- -------- ----------------------------------------
A NUMBER(38)
SQL> INSERT INTO t1_int VALUES(1234567890123456789012345678901234567890);
INSERT INTO t1 VALUES(1234567890123456789012345678901234567890)
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
/*1234567890123456789012345678901234567890共40位數*/
SQL> INSERT INTO t1_int VALUES(12345678901234567890123456789012345678);
SQL> INSERT INTO t2_int VALUES(12345678901234567890123456789012345678.9);
/*小數點後四捨五入*/
SQL> COMMIT;
SQL> SELECT * FROM frank.t1_int;
A
---------------
1.2346E+37
/*只是呈現的樣式如此,其實真的存入12345678901234567890123456789012345678的數值*/
SQL> SELECT * FROM frank.t2_int;
A
---------------
1.2346E+37
/*只是呈現的樣式如此,其實真的存入12345678901234567890123456789012345679的數值,因為小數點
後四捨五入,切記*/
SQL> SELECT DUMP(a) FROM frank.t1_int;
DUMP(A)
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
--------------------------------------------------------------------------------------------------------------
Typ=2 Len=20: 211,13,35,57,79,91,13,35,57,79,91,13,35,57,79,91,13,35,57,79
SQL> SELECT DUMP(a) FROM frank.t2_int;
DUMP(A)
--------------------------------------------------------------------------------------------------------------
Typ=2 Len=20: 211,13,35,57,79,91,13,35,57,79,91,13,35,57,79,91,13,35,57,80
SQL> SELECT t1.a-t2.a “T1-T2” FROM frank.t1_int,frank.t2_int;
T1-T2
--------
-1
SQL> SELECT t2.a-t1.a “T2-T1” FROM frank.t1_int,frank.t2_int;
T2-T1
--------
1
SQL> CREATE TABLE frank.t3_int(a INTEGER(10));
CREATE TABLE frank.t3_int(a INTEGER(10))
*
ERROR at line 1:
ORA-00907: missing right parenthesis
/*INTEGER一定是NUMBER(38,0),不能設定精確度*/
SQL> CREATE TABLE frank.t3_int (a INTEGER);
SQL> INSERT INTO frank.t3_int VALUES(123.4);
SQL> INSERT INTO frank.t3_int VALUES(234.5);
SQL> SELECT * FROM frank.t3_int;
A
-----------
123
235 /*切記小數點後會四捨五入,而不是無條件捨去*/
FLOAT
FLOAT 如同 INTEGER 一般,也是 NUMBER 的次型態,目前 FLOAT 的定義遵守的是 IEEE754 的標
準 。FLOAT 只能設定精確度(Precision)可由 1 到 126,但不能設定 Scale,但可以存入有小數的數值。
而且精確度並不是使用十進位呈現而是二進位。所以當 FLOAT(10)表示的是二進位精確度,需要轉成十
進位整數精確度,公式為二進位精確度*0.30103,若有小數則無條件進位。若要從十進位精確度轉成二
進位精確度,公式為十進位精確度*3.32193。
假設將 123.45 存入 FLOAT(5)的欄位中,則儲存後的值為 120。
實際的過程如下:
計算真正的精確度:FLOAT(5)的十進位精確度為 5*0.30103=1.50515,進位到最近的整數為 2。
數值轉換:123.45=1.2345*10^2
,因為精確度不能超過 2 位數,同時進行四捨五入,所以數值變成
1.2*10^2=120。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
SQL> CREATE TABLE frank.t1_flt(a FLOAT(10,2));
CREATE TABLE frank.t1_flt(a FLOAT(10,2))
*
ERROR at line 1:
ORA-00907: missing right parenthesis
/*FLOAT不能指定Scale*/
SQL> CREATE TABLE frank.t1_flt(a NUMBER,b FLOAT,c FLOAT(5),d FLOAT(9),e FLOAT(10));
SQL> DESC frank.t1_flt
Name Null? Type
----------------------------------------------------------- -------- ----------------------------------------
A NUMBER
B FLOAT(126)
C FLOAT(5)
D FLOAT(9)
E FLOAT(10)
/*FLOAT的最大二進位精確度為126*/
SQL> INSERT INTO frank.t1_flt VALUES(123.45,123.45,123.45,123.45,123.45);
SQL> SELECT * FROM frank.t1_flt;
A B C D E
------------- ------------ ----------- ---------- ----------
123.45 123.45 120 123 123.5
/* FLOAT(126)的十進位精確度為126*0.30103=37.92978,進位後為38(十進位精確度)。
FLOAT(9)的十進位精確度為9*0.30103=2.70927,進位後為3。123.45=1.2345*10^2,因為數值有四捨五
入,所以4以後被捨棄,結果為123。
FLOAT(10)的十進位精確度為10*0.30103=3.0103,進位後為4。123.45=1.2345*10^2,因為數值有四捨
五入,導致4變成5,因此結果為123.5。*/
8.2.3 日期型態
日期型態顧名思意是用來儲存日期資料,不過並不是使用一般所看到的格式(2009-01-01)直接存到資料
庫中,而是先將日期轉換為 Julian Day(儒略日,Oracle 採用天文學的定義),再將資料儲存到資料庫。
Julian Day 從西元前 4712 年 1 月 1 日中午開始為 1,以後每過一天就加上 1。所以如果將 2004-09-
15 改為 Julian Day 值則為 2453264。Oracle 資料庫中合法的日期範圍由 4712 BC 1 月 1 日到 9999
AD 12 月 31 日。
DATE
DATE 是最常被使用的日期型態,它可以存放世紀、年、月、日、時、分、秒的資訊。固定需要 7 個
Bytes 空間儲存 DATE 型態的資料。
SQL> SELECT TO_CHAR(TO_DATE('2004-09-15','YYYY-MM-DD'),'J') julian_days FROM dual;
JULIAN_
-----------
2453264
SQL> SELECT TO_CHAR(TO_DATE('01-01-4712 BC','DD-MM-YYYY BC'),'J') julian_days FROM dual;
JULIAN_
-----------
0000001
SQL> SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS') FROM dual;
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
TO_CHAR(SYSDATE,'YY
--------------------------------
2009-03-10 11:59:53
TIMESTAMP
從 Oracle9i 開始,Oracle 推出一種新的時間型態:TIMESTAMP。並且可以分成 TIMESTAMP、
TIMESTAMP WITH TIME ZONE 與 TIMESTAMP WITH LOCAL TIME ZONE 三種。
TIMESTAMP:可以儲存世紀、年、月、日、時、分、秒以及小數秒(最多可達小數點後 9 位)。需要 11
個 Bytes 空間儲存 TIMESTAMP 型態的資料。
TIMESTAMP WITH TIME ZONE:除了儲存 TIMESTAMP 的所有資訊外,另外還儲存時區(TIME ZONE)
資訊,所以需要多達 13 個 Bytes 的空間。
TIMESTAMP WITH LOCAL TIME ZONE:所欲儲存的 TIMESTAMP 資料先依資料庫端的時區,轉換為
資料庫端的 TIMESTAMP 格式,才儲存到資料庫中。當客戶端讀取該時間資訊時,自動將時間資料依客
戶端的時區資料轉換為 TIMESTAMP 格式呈現。需要 11 個 Bytes 的空間存放資料。
SQL> CREATE TABLE frank.t1_times(a TIMESTAMP,b TIMESTAMP WITH TIME ZONE,c TIMESTAM
P WITH LOCAL TIME ZONE);
SQL> INSERT INTO frank.t1_times VALUES(SYSTIMESTAMP,SYSTIMESTAMP,SYSTIMESTAMP);
SQL> SELECT SESSIONTIMEZONE FROM dual;
SESSIONTIMEZONE
---------------------------------------------------------------------------
+08:00 /*目前SESSION的時區*/
SQL> SELECT * FROM frank.t1_times;
------------------------------------------------------------------
12-MAR-09 02.23.49.029445 PM
12-MAR-09 02.23.49.029445 PM +08:00
12-MAR-09 02.23.49.029445 PM
SQL> ALTER SESSION SET TIME_ZONE='-07:00';
/*將SESSION的時區改為-07:00*/
SQL> SELECT * FROM frank.t1_times;
-----------------------------------------------------------------
12-MAR-09 02.23.49.029445 PM
12-MAR-09 02.23.49.029445 PM +08:00
11-MAR-09 11.23.49.029445 PM
/*TIMESTAMP WITH LOCAL TIME ZONE的時間會自動依客戶端的時區而調整*/
8.2.4 LOB(Large Object)
LOB 型態用來儲存大型資料。文字型態可以使用 CLOB(Character LOB)或 NCLOB(National Character
LOB),依所使用的字元集分類。二進位資料則可以使用 BLOB(Binary LOB)或 BFILE(Binary FILE)。
CLOB、NCLOB 與 BLOB 最大可儲存(4Giga Bytes-1)*Block_size 的資料,而 BFILE 最大可達 4Giga
Bytes。
文字大型物件(CLOB/NCLOB)
當資料大於 4000Bytes 時,一般的 VARCHAR2 或 NVARCHAR2 已經無法容納這麼大的資料。因此必
須使用 CLOB 或 NCLOB 來存放這些文字型態的資料。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
二進位大型物件(BLOB)
當二進位資料超過 2000Bytes 時,便不能使用 RAW 的型態儲存,必須改用 BLOB 的型態。必須使用
DBMS_LOB 來操作其內容,不能直接使用 SQL 指令操作。
二進位檔案(BFILE)
BFILE 是用來儲存資料,與 CLOB/BLOB 不同的地方在於:
1.資料存放的位置不在資料庫中,而是在檔案系統的檔案中。所以 BFILE 欄位值只存放相對的檔案位置
(目錄物件名字與檔案名字),而不是真正的資料內容。BFILE 所使用的檔案格式可以為 GIF、JEPG、
JPG、MEPG、MPEG2、TEXT、AVI 或其他的格式。
2.因此 BFILE 的內容不能使用 SQL 指令修改,只能用在查詢操作。如果要更改 BFILE 內容,必須使用
正確儲存格式的編輯器修改。例如 AVI 格式需要使用影片編輯軟體修改其內容。
BFILE 所使用的檔案最大不能超做 4G Bytes。
8.2.5 資料列 id(Rowid)
資料列 id(rowid)是一個虛擬的欄位值,它並不存在於資料庫中,所以不會佔用資料列的空間。當每筆資
料列產生後,就有一個唯一的資料列 id 存在。資料列 id 用來表示資料列在資料庫的相對位置,而不是絕
對位置,只要使用資料列 id 可以直接找到包含該資料列的資料區塊。因此透過資料列 id 存取資料庫是存
取速度最快的方法,也是成本最低的方法。
然而資料列 id 的格式對人類來說相當難以記憶,因此資料庫才提供索引,將對人類較有意義的欄位值與
該資料列的資料列 id 組成索引項目儲存在索引。之後只要提供索引鍵欄位值,就可以透過索引取得該資
料列得資料列 id,使用資料列 id 讀取資料列。然而這種方法較直接使用資料列 id 來的慢,而且需要索引
的空間與維護成本。
資料列 id 分為實體資料列 id(Physical ROWID)與邏輯資料列 id(Logical ROWID)。邏輯資料列 id 用在索
引組織表格上的索引,而其他非索引組織表格上的索引則使用實體資料列 id。
Oracle Database 11g 可以使用的實體資料列 id 有下面三種︰受限制的資料列 id(Restricted rowid),延
伸的資料列 id(Extended rowid),通用的資料列 id(Universal rowid)。
受限的資料列 id(RESTRICTED ROWID)
Oracle Database 7 所使用資料列 id 稱做受限的資料列 id,其顯示格式為 BBBBBB.RRRR.FFFF,如果
需要儲存則佔 6 Bytes(48 Bits)的空間。
其中 BBBBBB 為該資料列所在的資料區塊的號碼,需要佔 22 Bits 的空間,資料區塊號碼為資料檔的第
幾個資料區塊,而不是資料庫的第幾個資料區塊。RRRR 表示該資料列為資料區塊的第幾筆資料列,需要
佔 16 Bits 空間,資料列號碼由 0 開始。FFFF 為該資料列在資料庫的第幾個資料檔,需要佔 10 Bits 的
空間。因此可以得知 Oracle Database 7 的資料檔個數不能超過 2
10
-1 個(1023 個,因為 0 不能使用。),
當然也可以知道一個資料檔最多可以有 2
22
(400 萬)個資料區塊,每個資料區塊理論上可容納 2
16
(65536)
筆資料列。
當表格為非分區表格(Non-Partitioned Table)時,每個表格只有一個區段。因此平衡樹索引(B-tree Index)
的索引項目所使用資料列 id 為受限的資料列 id 即可。同時點陣圖索引(Bitmap Index)也使用受限的資料
列 id。
延伸的資料列 id(EXTENDED ROWID)
Oracle Database 8 時新增一種新的資料列 id 的格式,稱做延伸的資料列 id(Extended Rowid),從名字
來看就知道是因應受限的資料列 id 的不足。這種資料列 id 的格式為 OOOOOO.FFF.BBBBBB.RRR,如
果需要儲存則需要 10 Bytes(80 Bits)的空間。其中用 OOOOOO 為該區段(Segment)的物件
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
id(DATA_OBJECT_ID)佔 32 Bits,FFF 為表格空間的資料檔號碼(relative file number)佔 10 Bits,
BBBBBB 為該資料列所在的資料區塊的號碼佔 22 Bits,RRRR 為該資料列為該資料區塊的第幾筆資料列
佔 16 Bits。
延伸的資料列 id 與受限的資料列 id 的差異,為延伸的資料列 id 多儲存了區段的物件 id。以及延伸的資料
列 id 所使用的檔案號碼為相對的檔案號碼,而受限的資料列 id 所使用的檔案號碼為絕對的檔案號碼。相
對的檔案號碼表示這個資料檔案為表格空間的第幾個資料檔,絕對的檔案號碼表示此資料檔為資料庫的第
幾個資料檔。不過在整個資料庫的資料檔個數在 1023 以下時,相對的檔案號碼與絕對的檔案號碼一樣。
因此當表格的區段分別存放在不同表格空間時,便可以使用區段的物件 id 得知所在的表格空間。所以在
分區表格上建立索引,索引項目所使用的資料列 id 就是延伸的資料列 id。因為在分區表格下,每個分區
都是一個區段,也就是說分區表格由多個區段組成。
延伸的資料列 id 以 Base 64 編碼方式呈現,也就是資料列 id 將由 A-Z,a-z,0-9,+,/等字元所組成。
以下為字元與數值的對應表。
字
元
A B C D E F G H I J K L M
數
值
0 1 2 3 4 5 6 7 8 9 10 11 12
字
元
N O P Q R S T U V W X Y Z
字
元
13 14 15 16 17 18 19 20 21 22 23 24 25
符
號
a b c d e f g h i j k l m
字
元
26 27 28 29 30 31 32 33 34 35 36 37 38
字
元
n o p q r s t u v w x y z
數
值
39 40 41 42 43 44 45 46 47 48 49 50 51
字
元
0 1 2 3 4 5 6 7 8 9 10 + /
數
值
52 53 54 55 56 57 58 59 60 61 62 63 64
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
邏輯資料列 id(Logical ROWID)
邏輯資料列 id 用在索引組織表格(Index Organization Index)上的索引,因為在索引組織表格上的資料列
並不會永遠儲存在同一個位置,資料列將隨主鍵值而更換儲存位置。因此在索引組織表格上建立索引時,
使用邏輯資料列 id。邏輯資料列 id 由實體猜測位置(Physical Guess DBA)與主鍵值(Primary Key)所組成。
實體猜測位置是建立索引時,該筆資料列所在的資料區塊位置。
通用的資料列 id(UNIVERSAL ROWID)
通用的資料列 id 是 Oracle Database 8i 開始使用的資料列 id 型態,可以用來儲存實體資料列 id、邏輯資
料列 id 與外部表格(含非 Oracle 資料表)的資料列 id。通用的資料列 id 最大可達 4000 Bytes。
8.2.6 虛擬欄位
由 Oracle Database 11g 開始,可以宣告一種欄位型態:虛擬欄位,這種欄位並沒有真正的消耗儲存空
間,只有存在於表格定義中。當此欄位被查詢時,才會使用欄位定義的公式計算欄位值。欄位定義的公式
可以包括任何合法的運算以及函數。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
SQL> CREATE TABLE frank.t1_vir
2 (a NUMBER,b NUMBER,c NUMBER GENERATED ALWAYS AS (a+b) VIRTUAL);
/*GENERATED ALWAYS是為語法容易看懂而存在,VIRTUAL也是相同用途。所以可以直接使用c NUMBE
R AS (a+b)即可*/
SQL> DESC frank.t1_vir /*這裡看不出來,是否有使用虛擬欄位*/
Name Null? Type
--------------------------------------------------------- ------ -------------
A NUMBER
B NUMBER
C NUMBER
SQL> SELECT column_name,data_type,data_default FROM dba_tab_columns
2> WHERE OWNER=’FRANK’ AND table_name='T1_VIR' ;
COLUMN_NAM DATA_TYPE DATA_DEFAULT
------------------- ----------------- --------------------------
A NUMBER
B NUMBER
C NUMBER "A"+"B" /*欄位公式*/
SQL> INSERT INTO frank.t1_vir VALUES(1,2,3); /*不能直接Insert/Update虛擬欄位的內容*/
INSERT INTO frank.t1_vir VALUES(1,2,3)
*
ERROR at line 1:
ORA-54013: INSERT operation disallowed on virtual columns
SQL> INSERT INTO frank.t1_vir VALUES(1,2);
INSERT INTO frank.t1_vir VALUES(1,2)
*
ERROR at line 1:
ORA-00947: not enough values
SQL> INSERT INTO frank.t1_vir(a,b) VALUES(1,2); /*必須如此才能新增成功*/
---或 INSERT INTO frank.t1_vir VALUES(1,2,DEFAULT);
1 row created.
SQL> SELECT * FROM frank.t1_vir;
A B C
----------- ---------- ----------
1 2 3
/*找出row真正存放的位置*/
SQL> SELECT dbms_rowid.rowid_relative_fno(rowid) file#,
2 dbms_rowid.rowid_block_number(rowid) block#
3 FROM frank.t1_vir WHERE a=1 AND b=2 AND c=3;
FILE# BLOCK#
------------ -----------
1 40378
--將Data Block內容dump到user tracefile
SQL> ALTER SYSTEM DUMP DATAFILE 1 BLOCK 40378;
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
SQL> SHOW PARAMETER user_dump_dest /*確認User tracefile的位置*/
NAME TYPE VALUE
----------------------------- --------- -------------------------------------------------------
user_dump_dest string /u03/diag/diag/rdbms/ora11g/ora11g/trace
/*找到伺服器處理作業(Server Process)在作業系統行程的號碼(OS Process ID)*/
SQL> SELECT spid FROM v$process
2 WHERE addr=(SELECT paddr FROM v$session
3 WHERE sid=(SELECT DISTINCT sid FROM v$mystat));
SPID
--------
5000 --這個行程號碼可能依環境不同而不同
SQL> !cat /u03/diag/diag/rdbms/ora11g/ora11g/trace/ora11g_ora_5000.trc
--tracefile格式為SID_ora_OSPID.trc
--從Data Block的內容來看,可以證明虛擬欄位-C,並未佔有任何空間。
block_row_dump:
tab 0, row 0, @0x1f85
tl: 9 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 02 /*A欄位*/
col 1: [ 2] c1 03 /*B欄位*/
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 40378 maxblk 40378
使用者自行定義函數(User Defined Function)
當虛擬欄位用到使用者自行定義函數(User Defined Function)時,必須確定函數是明確性(Deterministic),
即只要輸入相同的參數值,函數就一定回傳相同的結果。
SQL> CREATE OR REPLACE minus_10(x NUMBER) RETURN NUMBER
2 IS
3 BEGIN
4 RETURN x-10;
5 END;
6 /
SQL> CREATE TABLE frank.t2 (a NUMBER,b NUMBER,c NUMBER AS (minus_10(a+b)) VIRTUA
L);
CREATE TABLE frank.t2 (a NUMBER,b NUMBER,c NUMBER AS (minus_10(a+b)) VIRTUAL)
*
ERROR at line 1:
ORA-30553: The function is not deterministic
SQL> CREATE OR REPLACE minus_10(x NUMBER) RETURN NUMBER DETERMINISTIC
2 IS
3 BEGIN
4 RETURN x-10;
5 END;
6 /
SQL> CREATE TABLE frank.t2_vir (a NUMBER,b NUMBER,c NUMBER AS (minus_10(a+b)) VIRT
UAL);
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
虛擬欄位的操作
虛擬欄位在 Oracle Database 11g 中,被當作一般的欄位,所以除了不能直接新增、異動其內容外,其
餘的操作如:當做主鍵、建立索引等都可以正常使用。
SQL> CREATE INDEX frank.t1_vir_c_idx ON t1_vir(c);
SQL> SELECT index_name,index_type FROM dba_indexes
2 WHERE owner=’FRANK’ AND table_name='T1_VIR';
INDEX_NAME INDEX_TYPE
------------------------------- --------------------------------------
T1_VIR_C_IDX FUNCTION-BASED NORMAL
/*從INDEX_TYPE可以得知,當建立索引在虛擬欄位上時,所建立的索引為Function-Based形態*/
SQL> ALTER TABLE frank.t1_vir ADD CONSTRAINT t1_vir_c_pk PRIMARY KEY(c);
/ 可以當作Primary KEY*/
SQL> EXECUTE dbms_stats.gather_table_stats('FRANK','T1_VIR'); /*收集統計值*/
/*虛擬欄位也可以當作分區欄位,這種分區方式稱為Virtual Column-Based Partitioning*/
SQL> CREATE TABLE frank.t3_vir
2 (a NUMBER,b NUMBER,c NUMBER AS (a+b+100) VIRTUAL)
3 PARTITION BY RANGE (c)
4 (PARTITION p1 VALUES LESS THAN(150),
5 PARTITION p2 VALUES LESS THAN(250),
6 PARTITION p3 VALUES LESS THAN(350));
虛擬欄位的使用限制
目前虛擬欄位在使用上,還存在著一些限制:
1.僅適用在 Heap Organized Table 上,還不能用在 Index-Organized、Cluster、External、
Temporary 以及 Object 等表格上。
2.虛擬欄位不能參考其他的虛擬欄位,只能參考同一個表格中的真實欄位。
3.當使用函數時,此函數必須宣告為 Deterministic 以及回傳的資料型態必須為 Scalar。
4.虛擬欄位的資料型態不能為 PL/SQL 的資料形態、User Defined Type、LOB 以及 Long Raw 等型態。
8.3 表格的種類
表格用來儲存資料,根據不同型態的資料與存取的樣式,資料庫管理人員可以選擇不同型態的表格,來達
到最佳的儲存空間與存取效率。一般常見的表格型態為堆集組織表格(Heap Table),當然還可以依據不同
的需求建立如:分區表格(Partitioned Table)、索引組織表格(Index Organized Table)、叢集表格
(Cluster)、暫時表格(Temporary Table)與外部表格(External Table)等。
8.3.1 堆集組織表格(Heap Organized Table)
通常資料庫中最常見的表格型態就是堆集表格(Heap Table)也可以稱作一般表格(Regular Table)。當使用
這種表格時,資料庫管理人員無法控制資料列(Row)的位置,資料列根據可用區塊串列(Freelists)或自動
區段空間管理(ASSM)機制決定存放的資料區塊,也可以說在此種表格中資料是無特別的順序。當建立表
格時,基本上需要知道這個表格將放在哪個綱要(Schema)、哪個表格空間。當然表格的名字與欄位名稱
與資料型態也不可以不知道。
建立表格前,必須確定建立者擁有相關的權限以及表格空間配額(Quota)。如果是將表格建立在自己的綱
要下,僅需要 CREATE TABLE 的系統權限以及足夠的表格空間配額即可。若要將表格建立在其他的綱
要下,則需要 CREATE ANY TABLE 的系統權限以及表格擁有者必須有足夠的表格空間配額。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
綱要物件(Schema Object)的命名規則
所謂的綱要物件是指那些可以放在綱要中的物件,例如:表格、索引(Index)、視圖(View)、限制
(Constraint)、程序(Procedure)、函數(Function)、套件(Package)、觸發器(Trigger)等都是常見的綱要
物件。綱要其實是一個邏輯的容器,包含著屬於與綱要相同名字的使用者的所有物件的集合。因此當將一
個表格在 FRANK 的綱要下時,表示這個表格是屬於 FRANK 這個使用者擁有的物件。然而眾多的物件需
要許多不同的名字,以正確的辨別物件。因此需要一個命名規則來幫助資料庫管理人員記憶與方便管理這
些綱要物件。
物件名稱必須在 30 個 Bytes 之內。不過有少數例外,例如:資料庫名字只能有 8 個 Bytes,但是資料庫
連結(Database Link)可以多達 128 個 Bytes。
可以使用的字元僅限於 A 到 Z 或 a 到 z 的大小寫英文字母與 0 到 9 的阿拉伯數字,加上#、_、$這三
個特殊符號。若是資料庫連接還可以使用 . 與@兩種特殊字元。不過若在名字前後加上雙引號,則任何字
元都可使用,甚至空白也可以。
物件名稱不能使用資料庫的保留字,如 TABLE、INDEX 等。但若使用雙引號則不受此限。
物件名稱要以英文字母開頭,若使用雙引號不受此限。
物件名稱並沒有大小寫的差別,因為 Oracle 都會將物件名稱轉成大寫,才存到資料辭典。如果使用雙引
號則會保留原來的大小寫格式。
當使用雙引號包裹物件名稱時,未來使用該物件時,必須也要使用雙引號才能正確呼叫該物件。所以不建
議使用雙引號。
在同一個綱要下,以下幾種物件(TABLE/VIEW/SEQUENCE/Private
SYNONYM/PROCEDURE/FUNCTION/PACKAGE/MATERIALIZED VIEW/User-Defined Type)不能
使用相同的名稱,因為他們位於相同的命名空間(NameSpace)。但是不同綱要屬於不同的命名空間,所
以可以在 FRANK 綱要與 SCOTT 綱要中,都存在一個叫做 EMP 的表格。
以下的綱要物件(INDEX/CONSTRAINT/CLUSTER/TRIGGER/Private Database Link/DIMENSION)擁
有自己的命名空間,所以即便是同一個綱要中已有一個 EMP 表格,還是可以建立一個叫做 EMP 的索引
或限制。不過同一個命名空間中,不能有相同名稱的物件存在。
表格範例
當建立一個表格之前,首先要確定幾件事。
擁有 CREATE TABLE 權限或 CREATE ANY TABLE(將表格放到別人的綱要中)。
表格所在表格空間尚有足夠的配額。
此外還要決定表格所在的綱要、表格名稱、欄位名稱及欄位的資料型態與長度,而一個表格中最多可以
1000 個欄位。以下是建立堆集組織表格(Heap Organized Table)的範例。
SQL> CONNECT / AS SYSDBA
SQL> CREATE TABLE frank.t1 --schema.table_name,表示此表格要放在哪個綱要下。
2 (a NUMBER(4), --宣告欄位名稱與資料型態
3 b VARCHAR2(10),
4 c DATE DEFAULT SYSDATE) --設定欄位的預設值,預設值的資料型態必須與欄位相同。
5 ORGANIZATION HEAP --建立堆集組織表格,可以不用強調,因為堆疊表格為預設值。
6 TABLESPACE users; --此表格的區段(Segment)所放置的位置。
可以從DBA_TABLES/ALL_TABLES/USER_TABLES中查詢相關的資訊
SQL> SELECT owner,table_name,tablespace_name
2 FROM dba_tables
3 WHERE table_name='t1' and owner='frank';
no rows selected --表格名稱會轉換成大寫後,才存入資料辭典。
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
SQL> SELECT owner,table_name,tablespace_name
2 FROM dba_tables
3 WHERE table_name='T1' and OWNER='FRANK';
OWNER TABLE_NAME TABLESPACE_NAME
------------------------------ ----------------------------------- ------------------------------
FRANK T1 USERS
SQL> SELECT object_id,data_object_id,object_name,object_type
2 FROM dba_objects
3 WHERE owner='FRANK' and object_name='T1';
OBJECT_ID DATA_OBJECT_ID OBJECT_NAME OBJECT_TYPE
---------------- ------------------------- ----------------------- -------------------
84547 84547 T1 TABLE
/*在Oracle資料庫中每個物件都有一個獨一的物件ID(Object_Id),用來辨識物件,同時如果該物件是區段(se
gment)物件時,也會有一個資料物件ID(Data_Object_Id)用來辨識其所擁有的區段*/
SQL> SELECT segment_type,tablespace_name,header_file,header_block,bytes,blocks
2 FROM dba_segments
3 WHERE owner='FRANK' and segment_name='T1';
SEGMENT_TYPE TABLESPACE_NAME HEADER_FILE HEADER_BLOCK BYTES BLOCKS
----------------------- ------------------------------ -------------------- ------------------------- ------------- ---------------
TABLE USERS 4 889 65536 8
/*每個區段都可有DBA_SEGMENTS/ALL_SEGMENTS/USER_SEGMENTS中查知其相關的資訊,例如:S
EGMENT_TYPE可以得知該區段的型態為TABLE或INDEX等。 TABLESPACE_NAME則可以知道該區段所
使用的表格空間為何?而HEADER_FILE與HEADER_BLOCK則可以得到SEGMENT_HEADER所在的位
置。EXTENTS則顯示目前區段所被配置的擴充區段個數。BYTES與BLOCKS則顯示目前區段的大小,分別
以Bytes或Block個數呈現。*/
SQL> SELECT extent_id,file_id,block_id,blocks,bytes
2 FROM dba_extents
3 WHERE owner='FRANK' and segment_name='T1' and tablespace_name='USERS';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS BYTES
----------------- ------------- -------------- ------------- ----------
0 4 889 8 65536
/*此外也可以由DBA_EXTENTS/ALL_EXTENTS/USERS_EXTENTS中查知區段與擴充區塊的關係,例如:
EXTENT_ID表示該擴充區塊是區段中的第幾個擴充區塊。FILE_ID則表示該擴充區塊是由那個資料檔中取得
相關的資料區塊。BLOCK_ID表示該擴充區塊是由資料檔的第幾個資料區塊開始,BLOCKS則表示該擴充區
塊為幾個連續的資料區塊組成。*/
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
STORAGE 子句
建立表格時,可以利用 STORAGE 子句設定表格的擴充區塊(Extent)參數。一個表格直接限制其大小,
但是可以透過擴充區塊的設定,間接限制其大小。若沒有設定 STORAGE 參數,則會依照此表格所在的
表格空間設定值設定相關的 STORAGE 參數。
SQL> CREATE TABLE frank.t2
2 (a NUMBER,b VARCHAR2(10),c DATE)
3 TABLESPACE users
4 STORAGE(INITIAL 1M NEXT 1M PCTINCREASE 0 MINEXTENTS 1 MAXEXTENTS 100);
/* INITIAL 1M設定第一個EXTENT的大小。
NEXT 1M指定第二個EXTENT的大小。
PCTINCREASE 0表示第三個EXTENT的大小為上一個EXTENT(即第二個)*(1+pctincrease/100),並以此
類推,第四個的大小為第三個的大小*(1+PCTINCREASE/100)。
MINEXTENTS表示建立此區段時,至少要有配置幾個擴充區塊。
MAXEXTENTS表示此區段,最多不能超過幾個擴充區塊。*/
從Oracle11g之後可以使用一個新的STORAGE參數:MAXSIZE,直接指定這個表格的大小,不需要辛苦的
計算EXTENT的大小與個數。
SQL> CREATE TABLE frank.t2
2 (a NUMBER,b VARCHAR2(10),c DATE)
3 TABLESPACE users
4 STORAGE(MAXSIZE 10M); /*這個表格的總空間不能超過10M*/
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
	
8.3.2 暫時表格(Temporary Table)
一般的表格建立後,都會有相對的區段(Segment)產生,而且這個區段必須指定所在的表格空間。然而
Oracle8i 後新增一種表格型態:暫時表格(Temporary Table),此種表格不需事先建立區段,而是當每個
階段作業(Session)第一次將資料新增(INSERT)到該暫時表格時,才會在該階段作業所使用的暫時表格空
間或暫時表格事先設定的暫時表格空間上,建立一個暫時區段。因此一個暫時表格可能會有多個區段同時
存在,但是每個階段作業僅能存取自己產生的暫時區段,所以暫時區段不會被其他階段作業所存取。因此
當暫時表格進行異動時,不需要使用鎖定(Lock)以避免同時異動,因為沒有其他階段作業可以異動其內容,
也不用擔心暫時表格的內容被其他階段作業看到。如此可以減少資料異動時的操作成本,也提供資料私密
性的功能。同時暫時表格上可以建立索引、限制與授與物件權限等,也可以正常的執行 DDL 指令(除
Truncate 外)。
資料保存時限
ON COMMIT DELETE ROWS:
ON COMMIT DELETE ROWS 是暫時表格的預設參數,表示暫時表格中的資料僅在交易(Transaction)過
程中有效,當交易結束(COMMIT)時,暫時表格的暫時區段將自動被截斷(TRUNCATE)。
ON COMMIT PRESERVE ROWS:
ON COMMIT PRESERVE ROWS 表示,暫時表格的內容,可以跨越交易而存在,不過當該階段作業結束
時,暫時表格的暫時區段將會隨著階段作業結束而被丟棄,暫時表格中的資料自然也隨之丟棄。
SQL> CREATE GLOBAL TEMPORARY TABLE frank.t3
2 (a NUMBER,b VARCHAR2(10));
/*由於沒有指定所在的表格空間,因此暫時表格的暫時區段將會產生在使用者FRANK的暫時表格空間中。
而資料保存時限為ON COMMIT DELETE ROWS*/
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
SQL> CREATE GLOBAL TEMPORARY TABLE frank.t4
2 (a NUMBER,b VARCHAR2(10))
3 TABLESPACE tempfrank;
/*此暫時表格的暫時區段將會產生在暫時表格空間TEMPFRANK中。
而資料保存時限為ON COMMIT DELETE ROWS*/
SQL> CREATE GLOBAL TEMPORARY TABLE frank.t5
2 (a NUMBER,b VARCHAR2(10))
3 ON COMMIT PRESERVE ROWS;
/*由於沒有指定所在的表格空間,因此暫時表格的暫時區段將會產生在使用者FRANK的暫時表格空間中。
而資料保存時限為ON COMMIT PRESERVE ROWS*/
SQL> SELECT table_name,tablespace_name,duration
2 FROM dba_tables
3 WHERE owner='FRANK' AND table_name IN ('T3','T4','T5');
TABLE_NAME TABLESPACE_NAME DURATION
------------------------------ ----------------------------------- ----------------------------
T5 SYS$SESSION
T4 TEMPFRANK SYS$TRANSACTION
T3 SYS$TRANSACTION
SQL> COMMIT; /*結束交易*/
SQL> SELECT * FROM frank.t3;
no rows selected /*因為暫時表格中尚未有任何資料*/
SQL> SELECT * FROM frank.t5;
no rows selected /*因為暫時表格中尚未有任何資料*/
SQL> INSERT INTO frank.t3 VALUES(1,'A');
SQL> INSERT INTO frank.t5 VALUES(1,'A');
SQL> SELECT * FROM frank.t3;
A B
---------- ----------
1 A
SQL> SELECT * FROM frank.t5;
A B
---------- ----------
1 A
SQL> COMMIT; /*結束交易*/
SQL> SELECT * FROM frank.t3;
no rows selected /*因為frank.t3的保存期限為交易期間,所以當交易結束後,暫時表格也會被截斷*/
SQL> SELECT * FROM frank.t5;
A B
---------- ----------
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
1 A /*因為frank.t5的保存期限為階段作業期間,所以當交易結束後,暫時表格不會被截斷*/
SQL> exit /*結束此階段作業,此時frank.t5的暫時區段將為隨著階段作業的結束,而被丟棄*/
[oracle@ELinux ~]$ sqlplus frank/oracle
SQL> SELECT * FROM frank.t5;
no rows selected /*在此階段作業中,frank.t5尚未被新增任何資料,所以連暫時區段都還沒有產生*/
8.3.3 外部表格(External Table)
外部表格用來存取資料庫外的文字檔(Text File)或 Oracle 專屬格式檔內容。因此建立外部表格時,不會
產生區段、擴充區塊、資料區塊等儲存結構,只有表格相關的定義存放在資料辭典中。當存取外部表格時,
才透過相關設定從文字檔或 Oracle 專屬格式檔案中取得資料。同時因為資料存放在資料庫之外,所以僅
供查詢(Select),不能對外部表格內容進行異動(Insert/Update/Delete)。
目錄物件(Directory)
自 Oracle Database 9i 開始,Oracle 資料庫若需要存取檔案系統時,必須使用目錄物件以相對路徑的方
式存取檔案,以增加資料庫安全性。所以使用外部表格前,需要先建立目錄物件,並授權資料庫的使用者
可以讀寫該目錄物件下的檔案。
[oracle@ELinux ~]$ pwd
/home/oracle
[oracle@ELinux ~]$ mkdir external_demo
[oracle@ELinux ~]$ sqlplus / as sysdba
SQL> CREATE DIRECTORY external_demo AS '/home/oracle/external_demo';
/*若在UNIX環境下,請注意大小寫差異,因為UNIX的目錄與檔案名稱大小寫視作不同目錄或檔案。
SQL> GRANT READ,WRITE ON DIRECTORY external_demo TO frank;
/*授予frank可以讀、寫目錄物件下的檔案。
文字檔
從 Oracle Database 9i 開始,資料庫管理者便可以利用外部表格將當文字檔當作資料來源。此時需要使
用 ORACLE_LOADER 這個存取界面來讀取文字檔,其實 ORACLE_LOADER 透過 SQL*LOADER 的
幫助,因此相關的存取設定都與 SQL*LOADER 類似。ACCESS PARAMETERS 為整個外部表格定義中
最重要的一部份,包含如何將文字檔的資料對應到外部表格。其中 RECORDS DELIMITED 用來設定如
何將文字檔資料轉成一筆 Record,Record 為 Field 所組成的結構。FIELDS TERMINATED BY 決定如
何將 Record 分割成 Field。一般常見的是 FIELDS TERMINATED BY `,’即使用逗號將 Record 分割
成多個 Field。或者是 FIELDS TERMINATED BY WHITESPACE 則是使用空白來分割 Field。
[oracle@ELinux ~]$ cat /home/oracle/external_demo/emp.txt --測試範例文字檔
100,Frank,1999-05-15,15000
101,Linda,2004-09-16,20000
102,Gigi,2005-02-23,7800
103,Wilson,2007-09-06,10000
/*100,Frank,1999-05-15,15000為一個Record,Frank則為一個Field,Field之間依逗號為間隔*/
[oracle@ELinux ~]$ sqlplus frank/oracle
SQL> CREATE TABLE emp_ext
2 (empid NUMBER(4),
3 ename VARCHAR2(10),
4 hire_date DATE,
5 salary NUMBER(6))
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
6 ORGANIZATION EXTERNAL --宣告這是個外部表格
7 (TYPE ORACLE_LOADER --資料來源是文字檔,所以使用ORACLE_LOADER
8 DEFAULT DIRECTORY external_demo --文字檔所在目錄的相對目錄物件
9 ACCESS PARAMETERS --如何切割文字檔中的資料,以及如何對應到表格
10 (RECORDS DELIMITED BY NEWLINE --每筆Record以NEWLINE符號分隔,Record可視為Row
11 FIELDS TERMINATED BY ',' --每個Field以逗號為間隔
12 (empid,ename,hire_date DATE MASK 'YYYY-MM-DD',salary) --DATE MASK設定日期格式
13 )
14 LOCATION('emp.txt') --文字檔的名字
15 )REJECT LIMIT UNLIMITED --發生幾次錯誤後,讀取動作將會中斷。UNLIMITED為無限制
16 ;
SQL> DESC emp_ext
Name Null? Type
----------------------------------------------------- ----------- ----------------------------------------
EMPID NUMBER(4)
ENAME VARCHAR2(10)
HIRE_DATE DATE
SALARY NUMBER(6)
SQL> SELECT * FROM emp_ext;
EMPID ENAME HIRE_DATE SALARY
---------- -------------------- ---------------- ------------
100 Frank 15-MAY-99 15000
101 Linda 16-SEP-04 20000
102 Gigi 23-FEB-05 7800
103 Wilson 06-SEP-07 10000
SQL> SELECT object_id,data_object_id,object_type FROM user_objects
2 WHERE object_name='EMP_EXT';
OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
---------------- ------------------------- -------------------
89052 TABLE --沒有data_object_id表示這個物件沒有相對的區段。
SQL> SELECT extent_id,blocks,bytes FROM user_extents WHERE segment_name='EMP_EXT';
no rows selected --真的沒有此區段存在
/*除使用符號分割Field外,也可以使用固定寬度的方式分割Field*/
[oracle@ELinux ~]$ cat /home/oracle/external_demo/emp1.txt
100 Frank 1999-05-15 15000
101 Linda 2004-09-16 20000
102 Gigi 2005-02-23 7800
103 Wilson 2007-09-06 10000
[oracle@ELinux ~]$ sqlplus frank/oracle
SQL> CREATE TABLE emp1_ext
2 (empid NUMBER(4),
3 ename VARCHAR2(10),
4 hire_date DATE,
5 salary NUMBER(6))
6 ORGANIZATION EXTERNAL
7 (TYPE ORACLE_LOADER
8 DEFAULT DIRECTORY external_
9 ACCESS PARAMETERS
10 (RECORDS DELIMITED BY
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
11 FIELDS(empid(1:4),ename(6:15),hire_date(17:26) DATE mask 'YYYY-MM-DD',salary(28:33))
12 )
13 LOCATION('emp1.txt')
14 )REJECT LIMIT UNLIMITED
15 ;
/*使用固定寬度方式切割Record為Field,並對應到Column*/
SQL> SELECT * FROM emp_ext;
EMPID ENAME HIRE_DATE SALARY
---------- -------------------- ---------------- ------------
100 Frank 15-MAY-99 15000
101 Linda 16-SEP-04 20000
102 Gigi 23-FEB-05 7800
103 Wilson 06-SEP-07 10000
SQL> SELECT table_name,type_name FROM user_external_tables; --查詢有哪些外部表格
TABLE_NAME TYPE_NAME
------------------------------ ------------------------------
EMP_EXT ORACLE_LOADER
EMP1_EXT ORACLE_LOADER
	
Oracle 專屬格式檔
自 Oracle Database 10g 後,Oracle 增加一種新的外部表格格式,使用 Oracle 專屬格式檔案,而不是文
字檔。這種檔案是二進位格式,不過其中資訊是以 XML 格式存放。這種外部表格建立方式有兩種:
UNLOAD(卸載)與 LOAD(載入)。
卸載:使用 CTAS(Create Table As Select)語法建立一個新的外部表格,為何稱為卸載?原因為這個外
部表格的資料來源為子查詢(SubQuery),而將資料存放到某個 Oracle 專屬格式檔案中,而不是資料庫中
的另一個表格。
SQL> DESC emp
Name Null? Type
----------------------------------------------------- ----------- ----------------------------------------
EMPID NUMBER(3)
ENAME VARCHAR2(20)
HIRE_DATE DATE
SALARY NUMBER(7)
SQL> SELECT * FROM emp;
EMPID ENAME HIRE_DATE SALARY
---------- -------------------- ---------------- ------------
100 Frank 15-MAY-99 15000
101 Linda 16-SEP-04 20000
102 Gigi 23-FEB-05 7800
103 Wilson 06-SEP-07 10000
SQL> SELECT object_id,data_object_id,object_type FROM user_objects WHERE object_name='EMP';
OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
---------------- ------------------------- -------------------
89054 89054 TABLE --data_object_id不是空值,表示這是一個標準表格
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
SQL> SELECT extent_id,blocks,bytes FROM user_extents WHERE segment_name='EMP';
EXTENT_ID BLOCKS BYTES
---------------- ------------ ----------
0 8 65536 --此表格目前有一個擴充區塊
SQL> CREATE TABLE emp2_ext
2 ORGANIZATION EXTERNAL --宣告為外部表格
3 (TYPE ORACLE_DATAPUMP --檔案格式為Oracle專屬格式
4 DEFAULT DIRECTORY external_demo --使用external_demo這個目錄物件
5 LOCATION('emp2.dmp') --檔案的名字
6 )
7 AS
8 SELECT * FROM emp; --卸載的資料來源
SQL> DESC emp2_ext
Name Null? Type
----------------------------------------------------- ----------- ----------------------------------------
EMPID NUMBER(3)
ENAME VARCHAR2(20)
HIRE_DATE DATE
SALARY NUMBER(7)
SQL> SELECT * FROM emp2_ext;
EMPID ENAME HIRE_DATE SALARY
---------- -------------------- ---------------- ------------
100 Frank 15-MAY-99 15000
101 Linda 16-SEP-04 20000
102 Gigi 23-FEB-05 7800
103 Wilson 06-SEP-07 10000
SQL> SELECT object_id,data_object_id,object_type FROM user_objects
2 WHERE object_name='EMP2_EXT';
OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
---------------- ------------------------- -------------------
89055 TABLE --沒有data_object_id
SQL> SELECT default_directory_name,type_name FROM user_external_tables
2 WHERE table_name='EMP2_EXT';
DEFAULT_DIRECTORY_NAME TYPE_NAME
----------------------------------------- ------------------------------
EXTERNAL_DEMO ORACLE_DATAPUMP
--證實emp2_ext為外部表格,並且使用ORACLE_DATAPUMP界面存取檔案
SQL> SELECT directory_name,location FROM user_external_locations
2 WHERE table_name='EMP2_EXT'; --卸載後產生的檔案位置與名字
DIRECTORY_NAME LOCATION
---------------------------- -----------------
EXTERNAL_DEMO emp2.dmp
SQL> SELECT directory_path FROM dba_directories WHERE directory_name='EXTERNAL_DEMO';
DIRECTORY_PATH
--------------------------------------------------------------------------------------------------------------
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
/home/oracle/external_demo --檔案系統上真實目錄
SQL> !ls -l /home/oracle/external_demo/emp2.dmp
-rw-r----- 1 oracle oinstall 12288 Mar 27 17:00 /home/oracle/external_demo/emp2.dmp
--建立外部表格所產生出的Oracle專屬格式檔案,其中存放著emp2_ext表格的內容
載入:載入為建立一個外部表格,能夠對應到之前產生 Oracle 專屬格式檔案的內容,讓資料庫的使用者
不須將檔案內容載入資料庫,即可透過外部表格查詢其內容。
[oracle@ELinux ~]$ pwd
/home/oracle
[oracle@ELinux ~]$ mkdir ext_dir
[oracle@ELinux ~]$ cp /home/oracle/external_demo/emp2.dmp /home/oracle/ext_dir/emp3.dmp
[oracle@ELinux ~]$ ls -l /home/oracle/ext_dir/emp3.dmp
-rw-r----- 1 oracle oinstall 12288 3月 27 17:25 /home/oracle/ext_dir/emp3.dmp
[oracle@ELinux ~]$ sqlplus / as sysdba --因為要建立新的目錄物件
SQL> CREATE DIRECTORY ext_dir AS '/home/oracle/ext_dir';
SQL> GRANT READ,WRITE ON DIRECTORY ext_dir TO frank; --授權讓Frank可以讀寫ext_dir目錄物件
SQL> CONNECT frank/oracle --切換身份為frank
SQL> CREATE TABLE emp3_ext
2 (empid NUMBER(4),
3 ename VARCHAR2(10),
4 hire_date DATE,
5 salary NUMBER(6))
6 ORGANIZATION EXTERNAL
7 (TYPE ORACLE_DATAPUMP
8 DEFAULT DIRECTORY ext_dir
9 LOCATION('emp3.dmp')
10 )REJECT LIMIT UNLIMITED;
SQL> DESC emp3_ext
Name Null? Type
----------------------------------------------------- ----------- ----------------------------------------
EMPID NUMBER(3)
ENAME VARCHAR2(20)
HIRE_DATE DATE
SALARY NUMBER(7)
SQL> SELECT * FROM emp3_ext;
EMPID ENAME HIRE_DATE SALARY
------------- ---------------- ---------------- ------------
100 Frank 15-MAY-99 15000
101 Linda 16-SEP-04 20000
102 Gigi 23-FEB-05 7800
103 Wilson 06-SEP-07 10000
當外部表格建立以後,資料庫管理者可以透過 DBA_EXTERNAL_TABLES 查詢外部表格的屬性設定,
也可利用 DBA_EXTERNAL_LOCATIONS 的內容得知資料來源檔案的名字。如果想要知道表格一般資訊
則如同其他表格型態一樣,查詢 DBA_TABLES 即可。
由於外部表格的唯讀特性,因此 ALTER TABLE 的操作僅允許以下幾種:
變更 Reject limit:ALTER TABLE emp_ext REJECT LIMIT 10;
變更 Project 限制:ALTER TABLE emp_ext PROJECT COLUMN REFERENCED;
變更 Access Parameters:ALTER TABLE emp_ext ACCESS PARAMETERS(FIELDS
TERMINATED BY WHITESPACE);
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
變更 Location:ALTER TABLE emp_ext LOCATION(`emp.dat’);
8.4 限制條件(Constraint)
資料完整性(Data Integrity)是指表格中的資料遵守商業規則(Business Rule),意即表格中的資料經過一
些過濾,確定符合事先設定的規範。例如人事規章中規定,每位公司員工必須有一個不能重複的員工編號
以供辨識,同時員工必須歸屬某個已經存在的部門等。為達到此目標,可以使用下列的方法:
前端應用程式檢查:在將資料輸入資料表之前,先使用前端應用程式對資料進行檢查,確定符合資料符合
特定規則,才能存入資料表中。
後端資料庫觸發器檢查:在後端資料庫撰寫觸發器,當資料新增、異動、刪除時便會觸發資料檢查程序,
唯有符合規則的資料才能成功地新增、異動與刪除。
然而前兩種方法都是透過撰寫程式碼達到所需的功能,然而對資料庫管理人員來說,撰寫相關的程式可能
過於困難或麻煩。所以可以先使用資料庫內建的限制條件(Constraint)進行基本、簡單的檢查,當限制條
件做不到所要的功能時,才使用前端應用程式或後端資料庫的觸發器進行更複雜的處理與檢查。
使用限制條件有以下好處:
僅需要宣告即可,不須撰寫複雜的程式碼。
效率較程式碼來的好,因為由 Oracle 核心完成。
限制條件設定在資料庫端,所以任何前端應用程式都會受到規範,不會有遺漏。
8.4.1 限制條件的種類
Oracle 資料庫提供五種限制條件,讓使用者可以依需求選擇合適的限制。以下針對這五種限制條件進行
說明:
NOT NULL(不可為空值):NOT NULL 會限制欄位值不可以為空值。不過此種限制條件僅能針對單一欄
位。
UNIQUE KEY(唯一索引鍵):UNIQUE KEY 限制條件的欄位值必須是唯一,也就是欄位值不可與其他資
料列的欄位值重複,此種限制條件可以針對單一欄位或多個欄位所組成的複合值。
PRIMRAY KEY(主索引鍵):其實 PRIMARY KEY 是由 NOT NULL 與 UNIQUE KEY 所共同組成的,因
此欄位值不能為空值,也不能重覆。同時 PRIMARY KEY 限制可以針對一個欄位值或由多個欄位所組成
的複合值,不過一個表格僅能有一個 PRIMARY KEY 限制。若有其他欄位也需要如 PRIMARY KEY 限制
一般的功能,只能使用 NOT NULL 與 UNIQUE KEY 兩個限制結合來達到該要求。
FOREIGN KEY(外來索引鍵):FOREIGN KEY 這種限制條件是要求欄位值必須參考其他欄位中已有的內
容,不能隨心所欲地新增或異動欄位值,不過被參考的欄位必須已經有 PRIMARY KEY 或 UNIQUE KEY
限制條件存在。同時一般稱 FOREIGN KEY 所在的表格為子表格(CHILD TABLE),而被參考的表格為父
表格(PARENT TABLE)。
CHECK(檢查):此種限制是要求欄位值必須讓某個條件式為真(TRUE)後,才允許欄位新增或異動,此種
限制只能針對單一欄位。條件式的範例如下:CHECK(Salary>10000),此限制要求 Salary 欄位值必須
大於 10000。
宣告限制條件可以分成欄位層次(INLINE CONSTRAINT)與表格層次(OUT OF LINE CONSTRAINT)。
NOT NULL 只能使用欄位層次,但若為複合欄限制,則必須採用表格層次。同時採用欄位層次宣告限制
時,不需要在限制條件後加上欄位名稱,但表格層次則必須加上欄位名稱。此外限制條件的名字,可以藉
由 CONSTRAINT 參數設定,若沒有指定,則由 Oracle 伺服器自動產生-(SYS_Cnnnnn,nnnnn 為序列
號)。
SQL> CREATE TABLE frank.con_t1
2 (a NUMBER PRIMARY KEY, --欄位宣告後,立刻接著限制條件的宣告,此為欄位層次
3 b VARCHAR2(10),
4 c DATE,
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
5 CONSTRAINT con_t1_b_uk UNIQUE(b)); --待所有欄位都宣告後,才宣告限制條件,此為表格層次
SQL> CREATE TABLE frank.con_t2
2 (a NUMBER CONSTRAINT con_t2_a_pk PRIMARY KEY,--使用Constraint參數設定限制條件的名字
3 b VARCHAR2(10),
4 c NUMBER NOT NULL, -- NOT NULL只能使用Column Level
5 CONSTRAINT con_t2_bc_uk UNIQUE(b,c));
--由多個欄位組成的限制條件,必須使用表格層次且必須加上欄位名稱。
SQL> CREATE TABLE frank.con_t3
2 (a NUMBER REFERENCES frank.con_t2(a));
--FOREIGN KEY在欄位層次與表格層次的宣告有些與不同
SQL> CREATE TABLE frank.con_t4
2 (a NUMBER,
3 b NUMBER,
4 CONSTRAINT con_t4_a_fk FOREIGN KEY(a) REFERENCES frank.con_t2(a),
5 CHECK(b>10)); --沒有指定限制條件名稱,將由Oracle伺服器自動指派。
/*可以透過DBA_CONSTRAINTS/ALL_CONSTRAINTS/USER_CONSTRIANTS查知限制條件的相關資訊*/
SQL> SELECT owner,table_name,constraint_name,constraint_type
2 FROM dba_constraints
3 WHERE table_name LIKE 'CON_T%'
4 ORDER BY table_name;
OWNER TABLE_NAME CONSTRAINT_NAME C
------------ ---------------------- ------------------------------ ---
FRANK CON_T1 CON_T1_B_UK U --U表示為UNIQUE KEY
FRANK CON_T1 SYS_C0014764 P --P表示為PRIMARY KEY
FRANK CON_T2 CON_T2_BC_UK U
FRANK CON_T2 SYS_C0014766 C --C可能是CHECK或NOT NULL
FRANK CON_T2 CON_T2_A_PK P
FRANK CON_T3 SYS_C0014769 R --R是FOREIGN KEY
FRANK CON_T4 SYS_C0014770 C
FRANK CON_T4 CON_T4_A_FK R
SQL> SELECT constraint_name,constraint_type,search_condition
2 FROM dba_constraints
3 WHERE table_name LIKE 'CON_T%' AND constraint_type='C';
CONSTRAINT_NAME C SEARCH_CONDITION
------------------------------ --- ------------------------------
SYS_C0014766 C "C" IS NOT NULL --依search_condition來區分CHECK與NOT NULL
SYS_C0014770 C b>10 --這個限制條件為CHECK
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
ON DELETE 參數
在宣告 FOREIGN KEY 時,必須指定當父表格資料被刪除,子表格資料要如何處理。共分成以下三種方
式:
NO DELETE ACTION:當宣告外鍵時,沒有設定 ON DELETE 參數。表示若父表格的資料列被刪除或
PRIMARY KEY/UNIQUE 限制所在的欄位值被異動時,如果子表格中有任何 FOREIGN KEY 限制的欄位
值受到影響導致違反 FOREIGN KEY 限制條件,則對父表格的刪除或異動將出現錯誤以及自動倒回該操
作。只有被刪除或異動的欄位值沒有被任何 FOREIGN KEY 參考時,才能順利地被刪除或異動。
SQL> CONNCT / AS SYSDBA
SQL> CREATE TABLE frank.p_table --父表格
2 (a NUMBER CONSTRAINT p_tab_a_pk PRIMARY KEY,
3 b VARCHAR2(10));
SQL> CREATE TABLE frank.c_table --子表格
2 (a VARCHAR2(10),
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
3 b NUMBER CONSTRAINT c_tab_b_fk REFERENCES frank.p_table(a)); --沒有ON DELETE設定
--建立父表格的測試資料
SQL> INSERT INTO frank.p_table VALUES(1,'A');
SQL> INSERT INTO frank.p_table VALUES(2,'B');
SQL> INSERT INTO frank.p_table VALUES(3,'C');
SQL> COMMIT;
SQL> SELECT * FROM frank.p_table;
A B
---------- ----------
1 A
2 B
3 C
--建立子表格測試資料
SQL> INSERT INTO frank.c_table VALUES('A',1); --新增成功,因為P_TABLE的A欄位中有1這個值
SQL> INSERT INTO frank.c_table VALUES('B',10);
INSERT INTO frank.c_table VALUES('B',10)
*
ERROR at line 1:
ORA-02291: integrity constraint (FRANK.C_TAB_B_FK) violated - parent key not found
--新增失敗,因為P_TABLE的A欄位中並沒有10這個值
SQL> INSERT INTO frank.c_table VALUES('B',3);
SQL> COMMIT;
SQL> SELECT * FROM frank.c_table;
A B
---------- -----------
A 1
B 3
SQL> SELECT table_name,constraint_name,constraint_type,delete_rule,r_constraint_name
2 FROM dba_constraints
3 WHERE table_name IN ('P_TABLE','C_TABLE');
TABLE_NAME CONSTRAINT_NAME C DELETE_RU R_CONSTRAINT_NAME
------------------------------ ------------------------------ -- ---------------- ------------------------------
C_TABLE C_TAB_B_FK R NO ACTION P_TAB_A_PK
P_TABLE P_TAB_A_PK P
/* 當CONSTRAINT_TYPE為R時,R_OWNER/R_CONSTRAINT_NAME為這個外鍵所參考的限制名稱與限
制擁有者。由以上結果可以得知,C_TABLE的C_TAB_B_FK參考P_TABLE上的P_TAB_A_PK主鍵限制。同
時當父表格被刪除資料或異動主鍵值時,子表格不進行任何動作(DELETE_RULE為NO ACTION)*/
SQL> DELETE frank.p_table WHERE a=2;
1 row deleted. --因為沒有任何子表格的外鍵參考這個欄位值,所以父表格的刪除動作成功完成。
SQL> SELECT * FROM frank.p_table;
A B
---------- ----------
1 A
3 C
SQL> DELETE frank.p_table WHERE a=1;
DELETE frank.p_table WHERE a=1
*
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
ERROR at line 1:
ORA-02292: integrity constraint (FRANK.C_TAB_B_FK) violated - child record found
/*因為有至少一個子表格參考這筆資料列中的A欄位值*/
SQL> UPDATE frank.p_table SET a=2 WHERE a=3;
UPDATE frank.p_table SET a=2 WHERE a=3
*
ERROR at line 1:
ORA-02292: integrity constraint (FRANK.C_TAB_B_FK) violated - child record found
/*因為子表格中尚有欄位值參考這筆資料列中的A欄位值*/
SQL> DROP TABLE frank.p_table;
DROP TABLE frank.p_table
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
/*即便是刪除父表格時,也會受到外鍵的影響。必須先刪除子表格或使用CASCADE CONSTRAINTS的選
項,方可以順利刪除父表格*/
SQL> DROP TABLE frank.p_table CASCADE CONSTRAINTS;
Table dropped.
/*CASCADE CONSTRAINTS選項會將所有參考此父表格的所有外鍵限制刪除,但不會將子表格一起刪除*/
ON DELETE CASCASE:當設定此種選項後,父表格的資料列被刪除,相對的子表格資料列同時也會被
刪除。但若只有異動 PRIMRARY KEY 或 UNIQUE KEY 的欄位值,還是會檢查是否有子表格的欄位參考
這些欄位值,如果有被參考,依然會出現違反 Reference Integrity 的錯誤訊息。
SQL> CREATE TABLE frank.p_table --父表格
2 (a NUMBER CONSTRAINT p_tab_a_pk PRIMARY KEY,
3 b VARCHAR2(10));
SQL> CREATE TABLE frank.c_table --子表格
2 (a VARCHAR2(10),
3 b NUMBER CONSTRAINT c_tab_b_fk REFERENCES frank.p_table(a)
4 ON DELETE CASACDE);
--建立父表格的測試資料
SQL> INSERT INTO frank.p_table VALUES(1,'A');
SQL> INSERT INTO frank.p_table VALUES(2,'B');
SQL> INSERT INTO frank.p_table VALUES(3,'C');
SQL> COMMIT;
SQL> SELECT * FROM frank.p_table;
A B
---------- ----------
1 A
2 B
3 C
--建立子表格測試資料
SQL> INSERT INTO frank.c_table VALUES('A',1);
SQL> INSERT INTO frank.c_table VALUES('B',3);
SQL> COMMIT;
SQL> SELECT * FROM frank.c_table;
A B
---------- -----------
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
A 1
B 3
SQL> SELECT table_name,constraint_name,constraint_type,delete_rule,r_constraint_name
2 FROM dba_constraints
3 WHERE table_name IN ('P_TABLE','C_TABLE');
TABLE_NAME CONSTRAINT_NAME C DELETE_RU R_CONSTRAINT_NAME
------------------------------ ------------------------------ -- ---------------- ------------------------------
C_TABLE C_TAB_B_FK R CASCADE P_TAB_A_PK
P_TABLE P_TAB_A_PK P
--當DELETE_RULE為CASCADE,表示FOREIGN KEY的選項為ON DELETE CASCADE
SQL> DELETE frank.p_table WHERE a=1;
1 row deleted.
SQL> SELECT * FROM frank.p_table; --父表格
A B
---------- ----------
2 B
3 C
SQL> SELECT * FROM frank.c_table; --子表格中所有B欄位為1的資料列
A B
---------- -----------
B 3
SQL> UPDATE frank.p_table SET a=10 WHERE b='C';
UPDATE frank.p_table SET a=10 WHERE b='C'
*
ERROR at line 1:
ORA-02292: integrity constraint (FRANK.C_TAB_FK) violated - child record found
/*因為子表格中尚有欄位值參考這筆資料列中的A欄位值*/
	
ON DELETE SET NULL: 當設定此種選項後,父表格的資料列被刪除,相對的子表格資料列雖不會被
刪除,但 FOREIGN KEY 限制條件的欄位值將會被更改為 NULL(空值)。但若只有異動 PRIMRARY KEY
或 UNIQUE KEY 的欄位值,還是會檢查是否有子表格的欄位參考這些欄位值,如果有被參考,依然會出
現違反 Reference Integrity 的錯誤訊息。
SQL> CREATE TABLE frank.p_table --父表格
2 (a NUMBER CONSTRAINT p_tab_a_pk PRIMARY KEY,
3 b VARCHAR2(10));
SQL> CREATE TABLE frank.c_table --子表格
2 (a VARCHAR2(10),
3 b NUMBER CONSTRAINT c_tab_b_fk REFERENCES frank.p_table(a)
4 ON DELETE SET NULL);
--建立父表格的測試資料
SQL> INSERT INTO frank.p_table VALUES(1,'A');
SQL> INSERT INTO frank.p_table VALUES(2,'B');
SQL> INSERT INTO frank.p_table VALUES(3,'C');
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
SQL> COMMIT;
SQL> SELECT * FROM frank.p_table;
A B
---------- ----------
1 A
2 B
3 C
--建立子表格測試資料
SQL> INSERT INTO frank.c_table VALUES('A',1);
SQL> INSERT INTO frank.c_table VALUES('B',3);
SQL> COMMIT;
SQL> SELECT * FROM frank.c_table;
A B
---------- -----------
A 1
B 3
SQL> SELECT table_name,constraint_name,constraint_type,delete_rule,r_constraint_name
2 FROM dba_constraints
3 WHERE table_name IN ('P_TABLE','C_TABLE');
TABLE_NAME CONSTRAINT_NAME C DELETE_RU R_CONSTRAINT_NAME
------------------------------ ------------------------------ -- ---------------- ------------------------------
C_TABLE C_TAB_B_FK R SET NULL P_TAB_A_PK
P_TABLE P_TAB_A_PK P
--當DELETE_RULE為SET NULL,表示FOREIGN KEY的選項為ON DELETE SET NULL
SQL> DELETE frank.p_table WHERE a=1;
1 row deleted.
SQL> SELECT * FROM frank.p_table;
A B
---------- ----------
2 B
3 C
SQL> SELECT * FROM frank.c_table; --子表格中受影響的外鍵欄位值被改為NULL,但未被刪除
A B
---------- -----------
A
B 3
SQL> UPDATE frank.p_table SET a=10 WHERE b='C';
UPDATE frank.p_table SET a=10 WHERE b='C'
*
ERROR at line 1:
ORA-02292: integrity constraint (FRANK.C_TAB_FK) violated - child record found
	
外鍵欄位上的索引
由之前的範例與說明得知,有設定 ON DELETE CASCASE 或 ON DELETE SET NULL 時,父表格的
刪除會導致子表格的資料列被刪除或欄位值改為 NULL(空值),這時不光是父表格需要一些鎖定(Table
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
Level 的 Row Exclusive 及 Row Level 的 Exclusive) ,同時子表格上也需要一些鎖定(Lock)。至於需要
何種型態的子表格鎖定,根據 Foreign Key 限制條件所在的欄位上是否有索引存在而有所不同。如果
Foreign Key 的欄位上沒有索引存在,則在任何 ON DELETE 設定下,都會先取得子表格(Table Level
的 Share Row Exclusive)。然而在握有子表格 Share Row Exclusive 的期間,將會禁止其他 Session 對
子表格進行任何 DML 與 DLL 操作,直到釋放 Share Row Exclusive 為止。不過自 Oracle9i 後,當完成
對子表格刪除或異動後,立刻就降為 Row Exclusive(不會禁止其他 Session 對子表格的 DML,僅禁止
DDL 操作),所以整體的鎖定競爭已經比 Oracle9i 之前的版本少,但是若同時有多個 Session 對父表格
進行 DML 操作,這時子表格還有可能會有嚴重的鎖定競爭發生。
然而若在子表格的 Foreign Key 欄位上建立一個索引,對子表格的鎖定則直接就是 Row Exclusive(僅禁
止 DDL),不需要先取得 Share Row Exclusive,如此 ON DELETE 參數所造成的子表格鎖定競爭將大
幅減少。
--以SYSDBA身份登入
SQL> CONNECT / AS SYSDBA
SQL> SELECT sid,type,id1,id2,lmode,request FROM v$lock WHERE TYPE IN ('TX','TM');
no rows selected --目前整個資料庫中,暫時還沒有Table Level與Row Level的Lock發生
SQL> lock table frank.c_table in exclusive mode;
/*人工取得對子表格的Table Level Lock,exclusive mode為獨佔模式,不允許其他Session同時握有任何型
態的Table Level Lock在子表格上。這個動作只是為了解Parent Table與Child Table間的鎖定關係而做,正
式環境中盡量不要使用人工要求鎖定的操作,以免影響正常的鎖定行為。*/
SQL> SELECT sid,type,id1,id2,lmode,request FROM v$lock WHERE TYPE IN ('TX','TM');
SID TY ID1 ID2 LMODE REQUEST
----------- ---- -------------- ----------- ------------ --------------
253 TM 84747 0 6 0
SQL> SELECT owner,object_name,object_type FROM dba_objects WHERE object_id=84747;
OWNER OBJECT_NAME OBJECT_TYPE
------------------------------ ----------------------------------- ----------------------
FRANK C_TABLE TABLE
/*當LOCK TYPE為TM時,ID1為該物件的Object_ID*/

--開啟另一個Session
SQL> SELECT * FROM frank.p_table; --p_table為Parent Table
A B
---------- ----------
2 B
3 C
1 A
SQL> SELECT * FROM frank.c_table; --c_table為Child Table,Foreign Key為ON DEELET SET NULL
A B
---------- ----------
A 1
B 3
SQL> DELETE frank.p_table WHERE a=1;
/*因為frank.c_table已經被其他人握有Table Level:Exclusive Lock,所以現在正在等待frank.c_table上的L
ock*/

回到SYS的Session
SQL> select sid,type,id1,id2,lmode,request from v$lock where type in ('TX','TM');
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
SID TY ID1 ID2 LMODE REQUEST
----------- ---- -------------- ---------- ----------- --------------
238 TM 84745 0 3 0 --DML所取得的Row Exclusive
238 TM 84747 0 0 5 --想要取得的TM:Share Row Exclusive
253 TM 84747 0 6 0 --人工取得的TM:Exclusive
/*因為Child Table上已經有人取得Exclusive Lock,所以ON DELETE想要的Share Row Exclusive必須等
待,此外對Parent Table的DML操作已取得Row Exclusive。*/
SQL> SELECT owner,object_name,object_type FROM dba_objects WHERE object_id=84745;
OWNER OBJECT_NAME OBJECT_TYPE
------------------------------ ----------------------------------- ----------------------
FRANK P_TABLE TABLE
SQL> COMMIT; --釋放Child Table上的Exclusive Lock
SQL> SELECT sid,type,id1,id2,lmode,request FROM v$lock WHERE TYPE IN ('TX','TM');
SID TY ID1 ID2 LMODE REQUEST
----------- ---- -------------- ---------- ----------- --------------
238 TM 84745 0 3 0
238 TM 84747 0 3 0 --當取得SRX開始進行DML,之後立刻降級為RX
238 TX 524316 12486 6 0 --取得Table Lock後,接著取得Row Lock
8.4.2 限制條件的操作
新增或刪除限制條件
所有的限制條件都可以隨時新增或刪除,除了 NOT NULL 必須使用 ALTER TABLE MODIFY 的語法外,
其餘的限制條件可以使用表格層次的方法新增限制或 ALTER TABLE MODIFY 的語法新增限制。
SQL> CREATE TABLE frank.t1
2 (a NUMBER,
3 b VARCHAR2(10));
SQL> DESC frank.t1
Name Null? Type
----------------------------------------------------- -------------- ----------------------------------------
A NUMBER
B VARCHAR2(10)
SQL> ALTER TABLE frank.t1
2 MODIFY (a NUMBER CONSTRAINT t1_a_nn NOT NULL); --NOT NULL必須使用MODIFY
SQL> DESC frank.t1
Name Null? Type
----------------------------------------------------- -------------- ----------------------------------------
A NOT NULL NUMBER
B VARCHAR2(10)
SQL> ALTER TABLE frank.t1
2 ADD CONSTRAINT t1_a_pk PRIMARY KEY(a); --新增一個PRIMARY KEY限制條件
SQL> ALTER TABLE frank.t1
2 DROP CONSTRAINT t1_a_pk CASCADE;
/*刪除一個限制時,若該限制為PRIMARY KEY或UNIQUE KEY要加上CASCADE ,同時將子表格的FOREI
GN KEY限制條件刪除*/
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
8.4.3 限制條件的狀態
限制條件的狀態影響限制對新增資料的檢查與否以及對現存資料的驗證,其中根據 DISABLE/ENABLE
與 NOVALIDATE/VALIDATE 組成四種情況:
DISBALE NOVALIDATE:當限制條件的狀態為 DISABLE NOVALIDATE 時,表示雖然表格上有設定
限制條件,但是並不會對新增的資料列進行檢查,同時也不會驗證表格中已經存在資料列是否遵守限制。
也就是說限制條件只是一個宣告,但完全不會發生任何功能。
ENABLE NOVALIDATE:當限制條件的狀態為 ENABLE NOVALIDATE 時,表示新增的資料列必須遵
守限制條件的規範,才能新增到表格中,不過已經存在表格中的資料列並不一定要遵守限制條件的規範。
所以現在的表格中的資料,可能還有一些資料是違反限制條件的規範,但至少從現在開始新增的資料一定
會遵守限制條件的規範。
ENABLE VALIDATE:當限制條件的狀態為 ENABLE VALIDATE 時,表示新增的資料列必須遵守限制
條件的規範,才能新增到表格中,同時也驗證已經存在表格中的資料也都遵守限制條件的規範。這種狀態
是宣告限制條件的預設狀態。
DISABLE VALIDATE:當限制條件的狀態為 DISABLE VALIDATE 時,表示新增的資料列不須遵守限
制條件的規範,也可以新增到表格中,不過所以已經存在的資料一定遵守限制條件的規範。這樣的狀態有
一點自相矛盾,因為如果一筆違反限制條件的資料列成功新增到表格中,那麼要如何達到已經存在的資料
列一定遵守限制條件呢?最簡單的方法是禁止這個表格的 DML 操作,就不會有這種問題發生。所以當狀
態為 DISABLE VALIDATE 時,限制所在的表格是不允許被新增、異動或刪除。這種狀態是用在當表格
與分區表格(Partition Table)的區段(Segment)進行交換操作時,所有的限制條件都必須是此種狀態,才
能順利進行區段的交換。
SQL> DROP TABLE frank.t1; --刪除frank.t1表格
SQL> CREATE TABLE frank.t1
2 (a NUMBER CONSTRAINT t1_a_ck CHECK(a>=10),
3 b VARCHAR2(10));
SQL> SELECT status,validated FROM dba_constraints
2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK';
STATUS VALIDATED
------------------ -----------------
ENABLED VALIDATED --宣告限制條件的預設狀態
SQL> ALTER TABLE frank.t1 DISABLE NOVALIDATE CONSTRAINT t1_a_ck;
/*如果只有DISABLE表示為DISABLE NOVALIDATE。若限制條件為PRIMARY KEY或UNIQUE,需要加上C
ASCADE將子表格上FOREIGN KEY的狀態也改為DISABLE*/
SQL> SELECT status,validated FROM dba_constraints
2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK';
STATUS VALIDATED
------------------ ------------------------
DISABLED NOT VALIDATED
SQL> INSERT INTO frank.t1 VALUES(10,'A');
SQL> INSERT INTO frank.t1 VALUES(1,'B'); --1小於10,但依然可以成功新增,因為狀態為DISABLED
SQL> COMMIT;
SQL> SELECT * FROM frank.t1;
A B
------------ ----------
10 A
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
1 B
SQL> ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINT t1_a_ck;
ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINT t1_a_ck
*
ERROR at line 1:
ORA-02293: cannot validate (FRANK.T1_A_CK) - check constraint violated
/*已經存在的資料列中,有些違反限制條件的規範,所以不能將狀態設為VALIDATE。必須自行將違反限制條
件的資料進行清理後,才能將狀態設為VALIDATE*/
SQL> ALTER TABLE frank.t1 ENABLE NOVALIDATE CONSTRAINT t1_a_ck;
/*退而求其次地將狀態條件先設定為ENABLE NOVALIDATE,避免有更多違反限制條件的資料列被新增,之
後再將違反限制條件的資料列修正,再將狀態改為ENABLE VALIDATE即可。如果只有ENABLE則表示為EN
ABLE VALIDATE*/
SQL> SELECT status,validated FROM dba_constraints
2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK';
STATUS VALIDATED
------------------ ------------------------
ENABLED NOT VALIDATED
SQL> INSERT INTO frank.t1 VALUES(2,'C'); --2比10小,所以無法新增
INSERT INTO frank.t1 VALUES(2,'C')
*
ERROR at line 1:
ORA-02290: check constraint (FRANK.T1_A_CK) violated
SQL> INSERT INTO frank.t1 VALUES(20,'C');
SQL> COMMIT;
SQL> SELECT * FROM frank.t1;
A B
------------ ----------
10 A
1 B
20 C
	
找出那些資料列違反限制條件的規範,首先必須先建立一個表格 EXCEPTIONS,這個表格利用
$ORACLE_HOME/rdbms/admin/utlexpt1.sql 產生。再利用 ALTER TABLE EXCEPTIONS 語法將違
反某個限制條件的資料列 ROWID 填入 exceptions 表格,如此便可以得知哪些資料列違反限制條件。
SQL> @$ORACLE_HOME/rdbms/admin/utlexpt1.sql
SQL> DESC exceptions
Name Null? Type
----------------------------------------------------------- ----------------- ----------------------------------------
ROW_ID ROWID
OWNER VARCHAR2(30)
TABLE_NAME VARCHAR2(30)
CONSTRAINT VARCHAR2(30)
SQL> SELECT row_id FROM exceptions
2 WHERE owner='FRANK' AND table_name='T1' AND constraint='T1_A_CK';
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
no rows selected
SQL> ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINT t1_a_ck
2 EXCEPTIONS INTO exceptions; --將違反t1_a_ck的資料列ROWID新增到exceptions表格中
ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINT t1_a_ck
*
ERROR at line 1:
ORA-02293: cannot validate (FRANK.T1_A_CK) - check constraint violated
SQL> SELECT row_id FROM exceptions
2 WHERE owner='FRANK' AND table_name='T1' AND constraint='T1_A_CK';
ROW_ID
--------------------------------------------------------------------------------------------------------------
AAAUsOAAEAAAAP6AAB --這筆ROW違反t1_a_ck
SQL> SELECT search_condition FROM dba_constraints
2 WHERE constraint_name='T1_A_CK' AND table_name='T1' AND owner='FRANK';
SEARCH_CONDITION
--------------------------------------------------------------------------------
a>=10
SQL> SELECT * FROM frank.t1
2 WHERE rowid IN (SELECT row_id FROM exceptions
3 WHERE owner='FRANK' AND table_name='T1' AND constraint='T1_A_CK');
A B
----------- ----------
1 B
/*修正違反t1_a_ck的資料列,讓它遵守t1_a_ck的規範*/
SQL> UPDATE frank.t1 SET a=11 WHERE rowid='AAAUsOAAEAAAAP6AAB';
1 row updated.
SQL> SELECT * FROM frank.t1 WHERE rowid='AAAUsOAAEAAAAP6AAB';
A B
----------- ----------
11 B
SQL> DELETE exceptions WHERE owner='FRANK' AND table_name='T1' AND constraint='T1_A_CK';
/*清除exceptions表格中已經處理過的資料列*/
SQL> COMMIT;
SQL> SELECT * FROM frank.t1;
A B
----------- ----------
10 A
11 B
20 C
SQL> ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINTS t1_a_ck;
SQL> SELECT status,validated FROM dba_constraints
Chapter	8	Table	
Oracle	Database	11g	資料庫管理入門	
2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK';
STATUS VALIDATED
------------------ -----------------
ENABLED VALIDATED
/*未來新增的資料必須遵守限制條件,同時已經存在的資料列也經過驗證確定遵守限制條件的規範*/
SQL> ALTER TABLE frank.t1 DISABLE VALIDATE CONSTRAINT t1_a_ck;
SQL> SELECT status,validated FROM dba_constraints
2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK';
STATUS VALIDATED
------------------ -----------------
DISABLED VALIDATED --此種狀態下,表格不允許DML操作
SQL> INSERT INTO frank.t1 VALUES(40,'D');
INSERT INTO frank.t1 VALUES(40,'D')
*
ERROR at line 1:
ORA-25128: No insert/update/delete on table with constraint (FRANK.T1_A_CK) disabled and validate
d
8.4.4 不可延緩與可延緩的限制條件
當表格的限制條件狀態為 ENABLE 時,新增的資料列必須遵守限制條件的規範才能被新增。然而何時進
行這個檢查,分成 DML 指令結束(IMMEDIATE)或交易結束(DEFERRED)兩種。
NOT DEFERRABLE(不可延緩)
然而當建立限制條件時,如果沒有明確指定限制條件可以延緩(DEFERRABLE),則限制條件的狀態就只
能為不可延緩(NOT DEFERRABLE)。而且事後也不可以更改,必須刪除現存的限制條件,重新建立一個
可以延緩的限制條件。如此該限制條件只能在 DML 指令結束後,立刻檢查該 DML 指令的結果是否遵守
限制條件的規範,如果違反限制條件的規範,該 DML 指令的結果將立刻被倒回(ROLLBACK),但是整個
交易(Transaction)依然存在不會倒回。
SQL> CREATE TABLE frank.t2
2 (a NUMBER CONSTRAINT t2_a_pk PRIMARY KEY, --此限制條件預設為NOT DEFERRABLE
3 b VARCHAR2(10));
SQL> SELECT deferrable,deferred
2 FROM dba_constraints
3 WHERE owner='FRANK' AND table_name='T2' AND constraint_name='T2_A_PK';
DEFERRABLE DEFERRED
------------------------------- ----------------
NOT DEFERRABLE IMMEDIATE
SQL> INSERT INTO frank.t2 VALUES(1,'A');
SQL> INSERT INTO frank.t2 VALUES(2,'B');
SQL> INSERT INTO frank.t2 VALUES(1,'C');
INSERT INTO frank.t2 VALUES(1,'C')
*
ERROR at line 1:
ORA-00001: unique constraint (FRANK.T2_A_PK) violated
/*此INSERT違反PRIMARY KEY,因此該INSERT的結果被倒回(ROLLBACK),但整個交易並未倒回或確認
(COMMIT)*/
SQL> SELECT * FROM frank.t2; --並未倒回整個交易
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹
Oracle 表格介紹

More Related Content

What's hot

Oracle Database Management - Backup/Recovery
Oracle Database Management - Backup/RecoveryOracle Database Management - Backup/Recovery
Oracle Database Management - Backup/RecoveryChien Chung Shen
 
Oracle Database Management Basic 1
Oracle Database Management Basic 1Oracle Database Management Basic 1
Oracle Database Management Basic 1Chien Chung Shen
 
Oracle Database Performance Tuning Concept
Oracle Database Performance Tuning ConceptOracle Database Performance Tuning Concept
Oracle Database Performance Tuning ConceptChien Chung Shen
 
Oracle Advanced Security Transparent Data Encryptionのご紹介
Oracle Advanced Security Transparent Data Encryptionのご紹介Oracle Advanced Security Transparent Data Encryptionのご紹介
Oracle Advanced Security Transparent Data Encryptionのご紹介オラクルエンジニア通信
 
Mvcc (oracle, innodb, postgres)
Mvcc (oracle, innodb, postgres)Mvcc (oracle, innodb, postgres)
Mvcc (oracle, innodb, postgres)frogd
 
Oracle Database SQL Tuning Concept
Oracle Database SQL Tuning ConceptOracle Database SQL Tuning Concept
Oracle Database SQL Tuning ConceptChien Chung Shen
 
Oracle Database Appliance 12.1.2.3.0 アップデート及びパッチ管理について
Oracle Database Appliance 12.1.2.3.0 アップデート及びパッチ管理についてOracle Database Appliance 12.1.2.3.0 アップデート及びパッチ管理について
Oracle Database Appliance 12.1.2.3.0 アップデート及びパッチ管理についてオラクルエンジニア通信
 
簡単!AWRをEXCELピボットグラフで分析しよう♪
簡単!AWRをEXCELピボットグラフで分析しよう♪簡単!AWRをEXCELピボットグラフで分析しよう♪
簡単!AWRをEXCELピボットグラフで分析しよう♪Yohei Azekatsu
 
Oracle Performance Tuning Fundamentals
Oracle Performance Tuning FundamentalsOracle Performance Tuning Fundamentals
Oracle Performance Tuning FundamentalsEnkitec
 
Performance Tuning Using oratop
Performance Tuning Using oratop Performance Tuning Using oratop
Performance Tuning Using oratop Sandesh Rao
 
Oracle sql high performance tuning
Oracle sql high performance tuningOracle sql high performance tuning
Oracle sql high performance tuningGuy Harrison
 
Oracle GoldenGate 19c を使用した 簡単データベース移行ガイド_v1.0
Oracle GoldenGate 19c を使用した 簡単データベース移行ガイド_v1.0Oracle GoldenGate 19c を使用した 簡単データベース移行ガイド_v1.0
Oracle GoldenGate 19c を使用した 簡単データベース移行ガイド_v1.0オラクルエンジニア通信
 
Oracle RAC 19c and Later - Best Practices #OOWLON
Oracle RAC 19c and Later - Best Practices #OOWLONOracle RAC 19c and Later - Best Practices #OOWLON
Oracle RAC 19c and Later - Best Practices #OOWLONMarkus Michalewicz
 
障害とオペミスに備える! ~Oracle Databaseのバックアップを考えよう~
障害とオペミスに備える! ~Oracle Databaseのバックアップを考えよう~障害とオペミスに備える! ~Oracle Databaseのバックアップを考えよう~
障害とオペミスに備える! ~Oracle Databaseのバックアップを考えよう~Shinnosuke Akita
 
MAA Best Practices for Oracle Database 19c
MAA Best Practices for Oracle Database 19cMAA Best Practices for Oracle Database 19c
MAA Best Practices for Oracle Database 19cMarkus Michalewicz
 
Understanding Oracle RAC 12c Internals OOW13 [CON8806]
Understanding Oracle RAC 12c Internals OOW13 [CON8806]Understanding Oracle RAC 12c Internals OOW13 [CON8806]
Understanding Oracle RAC 12c Internals OOW13 [CON8806]Markus Michalewicz
 
Oracle Latch and Mutex Contention Troubleshooting
Oracle Latch and Mutex Contention TroubleshootingOracle Latch and Mutex Contention Troubleshooting
Oracle Latch and Mutex Contention TroubleshootingTanel Poder
 

What's hot (20)

Oracle Database Management - Backup/Recovery
Oracle Database Management - Backup/RecoveryOracle Database Management - Backup/Recovery
Oracle Database Management - Backup/Recovery
 
Oracle SQL 1 Day Tutorial
Oracle SQL 1 Day TutorialOracle SQL 1 Day Tutorial
Oracle SQL 1 Day Tutorial
 
Oracle Database Management Basic 1
Oracle Database Management Basic 1Oracle Database Management Basic 1
Oracle Database Management Basic 1
 
Oracle Database Performance Tuning Concept
Oracle Database Performance Tuning ConceptOracle Database Performance Tuning Concept
Oracle Database Performance Tuning Concept
 
Oracle Advanced Security Transparent Data Encryptionのご紹介
Oracle Advanced Security Transparent Data Encryptionのご紹介Oracle Advanced Security Transparent Data Encryptionのご紹介
Oracle Advanced Security Transparent Data Encryptionのご紹介
 
Mvcc (oracle, innodb, postgres)
Mvcc (oracle, innodb, postgres)Mvcc (oracle, innodb, postgres)
Mvcc (oracle, innodb, postgres)
 
Oracle Database SQL Tuning Concept
Oracle Database SQL Tuning ConceptOracle Database SQL Tuning Concept
Oracle Database SQL Tuning Concept
 
Oracle Data Masking and Subsettingのご紹介
Oracle Data Masking and Subsettingのご紹介Oracle Data Masking and Subsettingのご紹介
Oracle Data Masking and Subsettingのご紹介
 
Oracle Database Appliance 12.1.2.3.0 アップデート及びパッチ管理について
Oracle Database Appliance 12.1.2.3.0 アップデート及びパッチ管理についてOracle Database Appliance 12.1.2.3.0 アップデート及びパッチ管理について
Oracle Database Appliance 12.1.2.3.0 アップデート及びパッチ管理について
 
Zero Data Loss Recovery Applianceのご紹介
Zero Data Loss Recovery Applianceのご紹介Zero Data Loss Recovery Applianceのご紹介
Zero Data Loss Recovery Applianceのご紹介
 
簡単!AWRをEXCELピボットグラフで分析しよう♪
簡単!AWRをEXCELピボットグラフで分析しよう♪簡単!AWRをEXCELピボットグラフで分析しよう♪
簡単!AWRをEXCELピボットグラフで分析しよう♪
 
Oracle Performance Tuning Fundamentals
Oracle Performance Tuning FundamentalsOracle Performance Tuning Fundamentals
Oracle Performance Tuning Fundamentals
 
Performance Tuning Using oratop
Performance Tuning Using oratop Performance Tuning Using oratop
Performance Tuning Using oratop
 
Oracle sql high performance tuning
Oracle sql high performance tuningOracle sql high performance tuning
Oracle sql high performance tuning
 
Oracle GoldenGate 19c を使用した 簡単データベース移行ガイド_v1.0
Oracle GoldenGate 19c を使用した 簡単データベース移行ガイド_v1.0Oracle GoldenGate 19c を使用した 簡単データベース移行ガイド_v1.0
Oracle GoldenGate 19c を使用した 簡単データベース移行ガイド_v1.0
 
Oracle RAC 19c and Later - Best Practices #OOWLON
Oracle RAC 19c and Later - Best Practices #OOWLONOracle RAC 19c and Later - Best Practices #OOWLON
Oracle RAC 19c and Later - Best Practices #OOWLON
 
障害とオペミスに備える! ~Oracle Databaseのバックアップを考えよう~
障害とオペミスに備える! ~Oracle Databaseのバックアップを考えよう~障害とオペミスに備える! ~Oracle Databaseのバックアップを考えよう~
障害とオペミスに備える! ~Oracle Databaseのバックアップを考えよう~
 
MAA Best Practices for Oracle Database 19c
MAA Best Practices for Oracle Database 19cMAA Best Practices for Oracle Database 19c
MAA Best Practices for Oracle Database 19c
 
Understanding Oracle RAC 12c Internals OOW13 [CON8806]
Understanding Oracle RAC 12c Internals OOW13 [CON8806]Understanding Oracle RAC 12c Internals OOW13 [CON8806]
Understanding Oracle RAC 12c Internals OOW13 [CON8806]
 
Oracle Latch and Mutex Contention Troubleshooting
Oracle Latch and Mutex Contention TroubleshootingOracle Latch and Mutex Contention Troubleshooting
Oracle Latch and Mutex Contention Troubleshooting
 

More from Chien Chung Shen

More from Chien Chung Shen (8)

Databases on AWS
Databases on AWSDatabases on AWS
Databases on AWS
 
Awsomeday ntc
Awsomeday ntcAwsomeday ntc
Awsomeday ntc
 
MySQL SQL Tutorial
MySQL SQL TutorialMySQL SQL Tutorial
MySQL SQL Tutorial
 
Oracle 12cR1 In-Memory Column Store
Oracle 12cR1 In-Memory Column StoreOracle 12cR1 In-Memory Column Store
Oracle 12cR1 In-Memory Column Store
 
Mssql to oracle
Mssql to oracleMssql to oracle
Mssql to oracle
 
Oracle Database Undo Segment Operation Concept
Oracle Database Undo Segment Operation ConceptOracle Database Undo Segment Operation Concept
Oracle Database Undo Segment Operation Concept
 
Hadoop Essential for Oracle Professionals
Hadoop Essential for Oracle ProfessionalsHadoop Essential for Oracle Professionals
Hadoop Essential for Oracle Professionals
 
Understanding index
Understanding indexUnderstanding index
Understanding index
 

Oracle 表格介紹

  • 1. Chapter 8 Table Oracle Database 11g 資料庫管理入門 第八章 表格 前言 Relational Database 一般翻譯為關連式資料庫,但這個中文翻譯常造成誤解,認為此種資料庫的表格 (Table)與表格之間一定存有某種關連(Relationship),因此才被稱作關連式資料庫。其實並不是如此,這 裡所說的關連(Relation)是 E.F.Codd 所用來當作儲存資料的結構,由於此種資料庫是由許多關連所組成, 所以才稱做關連式資料庫。本章節的重點便是介紹表格(Table),是資料庫用來儲存資料的結構,就是關 連式資料庫所謂的關連。 8.1 表格相關事項 在前面的章節中曾經提到,Oracle Database 在邏輯結構中,是由表格空間(Tablespace)所組成,表格空 間是由區段(Segment)所構成,區段為多個擴充區塊(Extent)的集合,而每個擴充區塊則為連續的資料區 塊(Data Block)所組成的。表格只是眾多區段的其中一種,然而卻是最重要的一種,因為所有的資料都存 放在表格中,無論是資料辭典(Data Dictionary)還是一般使用者的資料。 當一個表格初始建立時,其相關的定義如表格名稱、欄位名字、欄位型態以及限制條件等資訊是存放在資 料辭典中,而此表格的資料則需要儲存在額外空間。所謂的額外空間就是資料區塊,然而依 Oracle 資料 庫的規定,儲存空間的配置是以擴充區段為單位。所以一個表格建立之初,至少要配置一個擴充區塊以供 該表格儲存資料使用,區段則是屬於同一個表格的擴充區塊集合。不過當表格持續地被新增(Insert)、修 改(Update)、刪除(Delete)資料後,之前已配置的擴充區塊可能已經不敷使用,所以 Oracle 資料庫會自動 配置一個新的擴充區塊給該表格,直到該表格所能擁有的最大擴充區塊個數為止。 8.1.1 區塊的結構 資料區塊的結構可以分成三大部分:快取層(Cache Layer)、交易層(Transaction Layer)與資料層(Data Layer) 。根據不同的物件,其資料區塊的結構有著些許的不同,此處以表格區塊為範例。 快取層(Cache Layer) 快取層中存放著此區塊位置(Data Block Address)、區塊型態(Block Type:TABLE/INDEX、UNDO、 TEMPORARY)、區塊格式(Block Format:v7/v8),系統改變號碼(System Change Number-縮寫為 SCN)以及區塊尾端(Tail:存放此區塊中最後 4 個 Bytes 資料,用來與區塊註腳(Block Footer)的內容比 對,檢查區塊內容是否正確)。此區域固定佔 20 Bytes 的空間。
  • 2. Chapter 8 Table Oracle Database 11g 資料庫管理入門 交易層(Transaction Layer) 交易層分為固定的交易層(Fixed Transaction Layer)與變動的交易層(Variable Transaction Layer)。固 定的交易層顧名思義的表示此層的大小是固定,不因為任何因素而改變其大小。而變動的交易層的大小則 因為有關係的交易列表(Interested Transaction List-縮寫為 ITL)的個數,而有不同的大小。不過變動的 交易層一但佔用空間後,之後即便同時對此資料區塊異動的交易數量減少,也不會減少 ITL 的數量,也就 是變動的交易層的空間只有可能增加,而不會減少。 固定的交易層:此區域放著資料區塊的型態(Block Type)、最後一次資料區塊進行清理(Block CleanOut) 的時間、 有幾個 ITL 在變動的交易層中。此外如果是可用區塊列表(Freelists)管理的表格區塊,則還有可 用區塊列表鏈結(FreeList Link)與可用空間的鎖定(FreeSpace Lock)。如果是自動區段空間管理 (Automatic Segment Space Management-縮寫為 ASSM)管理的表格區塊,則存放的是層級 1 的位元組 區塊(L1 Bitmap Block)的位置、區塊位置的範圍(DBA Range)與操作碼(OP Code),以及區塊的版本資 訊(Block Incarnation)。此區域固定佔 48 Bytes 的空間。 變動的交易層:這個區域用來放 Interested Transaction List(ITL),有時被稱做交易項目(Transaction Entry),每個 ITL 佔 24 Bytes 空間。當建立表格時,可以使用 INITRANS 指定初始的 ITL 個數,預設值 為 1。MAXTRANS 在 10g 之後自動設為 255,表示最多可有 255 個 ITL 存在。當每個交易 (Transaction)想要進行異動區塊內容,不論是新增、異動、刪除資料列時,首先必須找到可用的 ITL,將 交易相關的資訊填入 ITL 中,之後才可以進行後續的操作。不過已用過的 ITL 可以重複被使用,但已產 生的 ITL 個數將不會減少,所以 Oracle 伺服器會儘可能地重複使用那些已存在的 ITL。若找不到可用的 ITL,還是會新增一個 ITL,ITL 個數可多達 255。 一般所稱的資料區塊標頭(Block Header)是指快取層與交易層。 資料層(Data Layer) 表格目錄(Table Directory) 此結構的主要用途為當表格為叢集表格(Cluster Table:叢集表格由一個或多個表格組成),同一個叢集表 格的資料區塊中可能有著屬於不同表格的資料列(Row)。因此必須使用表格目錄的內容來找到屬於特定表 格的資料列。不過如果表格是非叢集型態,表格目錄中只有一個表格索引(Table Index)即可。但是叢集表 格則根據此叢集表格由幾個表格組成,決定需要幾個表格索引。而每個表格索引需要 4 Bytes 空間。 資料列目錄(Row Directory) 在這個表格中的每一筆資料列(Row)都有一個記錄在資料列目錄(Row Directory)中。因為存放在資料列 資料區域中的每個資料列之間,並沒有特別的間隔符號,所以每次想要讀取某個資料列時,需要提供該資 料列的資料列辨識碼(Row ID),其中的資料列號碼(Row Number)就是指定讀取資料列目錄的哪一筆記錄。 而該筆記錄的內容則記載著某筆資料列的資料列標頭的位置,利用資料列目錄的內容便可以由資料區塊找 出所要的資料列。 當一筆資料列被新增到此區塊時,須先找到可用的資料列目錄結構,如果沒有任何現有的結構可供使用, 則會增加一個資料列目錄結構,用來存放該筆資料列的資料列標頭在資料層(Data Layer)的位置,每個資 料列目錄結構需要 2 Bytes 的空間。然而若此區塊中的資料列被刪除後,則該筆資料列所使用的資料列目 錄結構則可以被重複被之後新增的資料列使用,不過資料列目錄所佔的空間不會縮小,即使有一大堆空的 資料列目錄結構存在。 所謂的區塊負擔(Block Overhead)是由區塊標頭(Block Header)、表格目錄(Table Directory)及資料列目 錄(Row Directory)組成。 可用空間(Free Space) 整個資料區塊空間扣除區塊負擔與資料列所佔用空間後,所剩餘的空間稱做可用空間(Free Space)。可用 空間可供新增資料列或因異動資料列(異動後的資料列長度較異動前來的大)使用。同時可用空間也可供區 塊負擔因 ITL 個數增加或資料列目錄結構增加而需要的空間。在這樣的兩面夾擊之下,可用空間將會逐漸 地減少。不過當有些資料列因為刪除或異動而導致資料列資料所佔空間減少時,可用空間將因此而增加。 然而需要注意的是,區塊負擔已經使用的空間,將不會因為任何原因而減少。 資料列資料(Row Data)
  • 3. Chapter 8 Table Oracle Database 11g 資料庫管理入門 由眾多的資料列片段(Row Piece)組成,也就是我們一般認知的資料列。資料列片段本身也是由資料列標 頭(Row Header)與欄位資料(Column Data)組成。 資料列標頭(Row Header)為資料列旗標(Row Flag)、鎖定位元組(Lock Byte)、欄位數量(Number Of Columns)、叢集索引(Cluster Index)、鏈結資訊(Chaining Information)所組成。 資料列旗標(Row Flag):用來儲存此筆資料列的狀態,是否為單一資料列片段組成或者為鏈結資料列片段 (Chaining Row Piece)的第一個片段還是最後一個片段,也可以顯示這筆資料列已經被刪除等訊息。資料 列旗標需要佔用 1 Byte 空間。 鎖定位元組(Lock Byte):記錄此筆資料列是否被某個交易鎖定,若該資料列正被某個交易鎖定,則鎖定 位元組中將會儲存某個區塊負擔的 ITL 位置,而該 ITL 中有鎖定該資料列的交易的交易辨識碼 (Transaction ID)。交易辨識碼由還原區段號碼(Undo Segment Number)、槽號碼(Slot Number)與順序 號碼(Sequence Number)組成。鎖定位元組需要 1 Byte 的空間。 欄位個數(Number Of Columns):用來記錄該資料列的欄位資料(Column Data)中有存在幾個存放欄位長 度(Column Length)的結構。欄位個數佔用 1 Byte 的空間。 叢集鍵值索引(Cluster Key Index):只有當此區塊為叢集表格的資料區塊時,才需要這個結構標示資料列 為哪個叢集表格的成員(Cluster Table Member)。叢集鍵值索引需要 1 Byte 的空間。 連結資訊(Chaining Information):當發生資料列遷移(Row Migration)或資料列鏈結(Row Chaining)時, 需要在資料列標頭中記錄另外的資料列片段的位置。鏈結資訊需要 6 Bytes 的空間,其中包含資料列片段 所在的區塊位置(Data Block Address)及該區塊標頭的資料列目錄位置(Row Number)。 如果此表格不是叢集表格,同時也沒有發生資料列遷移或資料列鏈結的情況,則資料列標頭等於資料列 負擔,只需要 3 Bytes 的空間(Row Flag/Lock Byte/# Of Cols)即可。 欄位資料(Column Data)為真正欄位值儲存的地方,但是每個欄位值需要使用一組欄位長度(Column Length)及欄位值(Column Value)來儲存。因為欄位與欄位之間沒有任何間隔符號,所以使用欄位長度來 說明該欄位值所佔的空間為多少。假設某個欄位長度的值為 10,表示欄位長度後的 10 Bytes 所儲存的 內容,為該欄位的值,也就是說該欄位值佔 10 Bytes 的空間。當欄位值(Column Value)所佔的空間在 250 Bytes 以下時,則相對應的欄位長度只需要 1 Byte 即可。若當欄位值(Column Value)所佔的空間超 過 250 Bytes 以上時,則欄位長度需要 3 Bytes 的空間。欄位值(Column Value)為空值(Null)時,則該欄 位的欄位長度的內容值將為 0,表示不需要欄位值(Column Value)。但若該空值的欄位為於資料列片段的 最後面,則連欄位長度都不需要儲存,以節省空間。 SQL> CREATE TABLE frank.test (a NUMBER,b NUMBER,c NUMBER); SQL> SELECT * FROM frank.test; A B C ----------- ------------ ---------- a 1 /*B欄位值為NULL*/ b /*B,C欄位值皆為NULL*/ --以下為表格frank.test的block dump tab 0, row 0, @0x1f97 tl: 9 fb: --H-FL-- lb: 0x1 cc: 3 /*fb為Flag Byte即Row Flag。cc為Number Of Columns */ col 0: [ 1] 61 /*[1]為Column Length,表示後面1 Byte為Column Value也就是61*/ col 1: *NULL* /*空值僅需要Column Length即可*/ col 2: [ 2] c1 02 /*[2]為Column Length,表示後面2 Byte為Column Value也就是c1 02*/ tab 0, row 1, @0x1f92 tl: 5 fb: --H-FL-- lb: 0x1 cc: 1 /*cc為1,表示此row piece中只存放1個欄位的值,因為B,C皆為空值*/ col 0: [ 1] 62 區塊尾部(Tail) 存放此資料區塊的最後 4 個 Bytes 資料,用來與儲存在快取層(Cache Layer)的區塊尾端資料比對,檢查 兩者是否一致。若兩者不一致,則會出現 ORA-01578 區塊毀損的錯誤訊息。
  • 4. Chapter 8 Table Oracle Database 11g 資料庫管理入門 8.1.2 資料列與區塊的關係 當一個表格被建立之後,至少會配置一個擴充區段。所以目前這個表格所有的列將會存放在擴充區塊中, 但因為擴充區塊為連續的資料區塊組成,所以列實際是存放在資料區塊中。表格是資料列(Row)的集合, 列是欄位(Column)所構成的,欄位是由欄位名字與資料型態組成。 資料列鏈結(Row Chaining) 由於 Oracle 資料庫進行 I/O 的最小單位是一個資料區塊,所以通常建議一筆資料列應該要小於該表格的 資料區塊大小,這樣在讀取一筆資料列時,只需要讀 1 個資料區塊即可,這樣可以減少 I/O 成本。但是 建立表格時,不能指定此表格所使用的資料區塊大小。因為資料區塊的大小是在建立表格空間時所設定, 所以在建立表格之前時,需要慎重地選擇所使用的表格空間。因為當新增(Insert)操作將資料列新增到表 格時,如果如果資料列的大小大於表格所使用的資料區塊大小,這時該資料列將被切割為數個資料列片段 (Row Piece),然後將資料列片段分別存放在不同的資料區塊。而這些資料列片段透過資料列表頭(Row Header)中的鏈結資料(Chaining Information)鏈結在一起,每個資料列片段的鏈結資料記錄著下一段的資 料列片段位置。所以當 Oracle 資料庫存取該資料行時,需要讀取多個資料區塊,才能將這筆資料列讀到 緩衝區快取(Buffer Cache)。因此整體的效能便受到拖累(因為 I/O 的數量增加)。 這種情況稱作資料列鏈接(Row Chaining),通常發生在新增操作居多,有時一些異動操作也會造成。發 生的原因可能是資料列太大或資料區塊太小,資料庫管理者可以透過正規化將資料列變小或將表格移動到 較大區塊的表格空間來解決資料列鏈結的問題。
  • 5. Chapter 8 Table Oracle Database 11g 資料庫管理入門 資料列遷移(Row Migration) 當一個資料區塊中已經存在的資料列,因為更新操作(Update)造成原本資料列變大。如果現在資料列所處 區塊的可用空間(Free Space)夠大,這筆資料列會依然位於現在的資料區塊中。但是若可用空間不夠大, 則 Oracle 資料庫會尋找另一個可用空間夠大的區塊(同一個區段),將整筆資料列都遷移到該區塊。但是因 為索引(Index)中已經將原來資料列的位置當成索引項(Index Entry)的一部份,所以資料庫在原本的資料 區塊中,將繼續保存原來的資料列標頭(Row Header),並將其中的鏈結資料(Chaining Info)填入新資料 列的位置,因此當 Oracle 資料庫透過索引存取該筆資料列時,會先讀取到建立索引當時,該資料列所在 的區塊,但是現在該資料列已經遷移到另一個資料區塊中,Oracle 資料庫只好再利用舊列表頭的鏈結資 料存取現在資料列的區塊,因此至少需要讀取兩個表格的資料區塊才能夠取得一筆資料列。
  • 6. Chapter 8 Table Oracle Database 11g 資料庫管理入門 這種情況稱做資料列遷移,並可以透過保留較大的可用空間解決,即增加表格的 PCTFREE 參數值。 PCTFREE 參數預設為 10,表示當一個資料區塊的可用空間佔資料區塊的比率(free space/block size)低 於 10%時,該資料區塊將被設定為滿區塊(Full Block),表示該資料區塊不能再被新增資料列,但是可以 被更新或刪除資料列。而所保留的可用空間便是提供空間給未來更新資料列時,可以用來容納更新後的資 料列。 若已經發生資料列遷移,則可以使用表格重組(Table Reorganization)來消弭資料列遷移的情況。因為表 格重組的操作,都是使用新增(Insert)的方法,而資料列遷移則是由更新(Update)所產生。所以經過表格 重組後,便可以消弭資料列遷移的問題。
  • 7. Chapter 8 Table Oracle Database 11g 資料庫管理入門 8.1.3 正規化(Normalization) 在資料庫設計的相關技巧中,正規化是管理人員耳熟能詳的基本技巧,而基本的正規化至少要達到第三正 規化,才有正規化的效果。正規化可以帶來以下的一些好處:1.避免資料重複。2.節省儲存空間。當然某 些情況下,正規化可能導致效能上的問題。這時可以適時地使用反正規化來增加整體的效能,不過在進行 反正規化之前,當然還是要先正規化,因為不是每個表格都需要反正規化。 第一正規化 (First Normal Form:1NF) 定義:每個表格中都要有主鍵(Primary Key)用以辨識資料列,而且表格中不能有重複的欄位,同時每個 欄位只能儲存一筆值。 說明:這個表格中學號可以用來當做 Primary Key,因為每個學生都有一個不重複的學號。但是各科成績 這個欄位內,儲存國文、英文、數學的資料,便違反第一正規化的每個欄位只能有一個值的限制。因此必 須將各科成績的欄位執分別存放到不同的欄位,例如:國文、英文、數學。現在這個表格已經符合第一正 規化的要求。 第二正規化(Second Normal Form:2NF) 定義:首先必定要滿足第一正規化的要求,而且表格中非主鍵的欄位,還必須跟主鍵有完全相依性。 說明:國文、數學、英文、總分都與學號有著完全的相依性。所以此表格也滿足第二正規化的要求。 額外說明︰假設某表格由學號、科目、成績、教室所組成。因為同一位學生有多個科目的成績,所以主鍵 學號與科目組成。同時每個欄位只有單一值,所以這個表格符合第一正規化。但是非主鍵欄位:上課教室, 只與主鍵中的科目相關,不與學號相關。這種情況稱作部份相依。而成績則與主鍵完全相依,因為每個成 學號 各科成績(國文,英文,數學) 總分 100 90,85,95 270 101 85,80,100 265 學號 國文 英文 數學 總分 100 90 85 95 270 101 85 80 100 265
  • 8. Chapter 8 Table Oracle Database 11g 資料庫管理入門 績都是以特定學號與特定科目為分別。因此為符合第二正規化的要求,需要將上課教室移出本表格,另外 建立一個表格由科目與上課教室組成,這樣才會符合第二正規化的要求。 科目 上課教室 國文 A 英文 B 數學 A 第三正規化(Third Normal Form:3NF) 定義:當滿足第二正規化後,非主鍵欄位之間不能存在相依性。 說明:因為總分為國文、英文、數學等欄位的加總,所以這些非主鍵欄位之間有相依性。所以必須將總分 欄位由表格中移除,另外建立一個表格由學號與總分組成 如此便可以滿足第三正規化的要求。 學號 總分 100 270 101 265 正規化所造成的問題 如果不建立總分表格: 由 AP 人員必須將計算公式(國文+數學+英文)寫到程式中,這種方法的好處是,表格依然維持正規的設計, 但是若計算公式一但有所變動,則需要修改程式內容,以及必須將新的程式部署到各個客戶端。 學號 科目 成績 上課教室 100 國文 90 A 100 英文 85 B 100 數學 95 A 101 國文 85 A 101 英文 80 B 101 數學 100 A 學號 科目 成績 100 國文 90 100 英文 85 100 數學 95 101 國文 85 101 英文 80 101 數學 100 學號 國文 英文 數學 總分 100 90 85 95 270 101 85 80 100 265 學號 國文 英文 數學 100 90 85 95 101 85 80 100
  • 9. Chapter 8 Table Oracle Database 11g 資料庫管理入門 建立一個視觀圖(VIEW),將計算公式產生總分的虛擬欄位(CREATE VIEW student_view AS SELECT 國文,數學,英文,(國文+數學+英文) as 總分 FROM student),這樣便可以透過視觀圖得到總分的資料。 這種方式的缺點是必須多花一些維護成本在視觀圖的管理上。 解決方案:自 Oracle Database11g 後可以採用虛擬欄位,解決此種問題。若使用反正規化的技巧解決此 問題。 如果建立總分表格: 必須使用結合(Join)指令才能得到各科成績與總分的結果,可能導致大量的結合指令發生,進而影響效能。 解決方案:可以使用叢集(Cluster)表格將兩個表格叢集起來,讓操作結合指令時,可以減少資料區塊的 I/O 量。也可以使用反正規化的技巧解決此問題。 反正規化 資料庫管理者也可以在 Student 表格上,多加一個總分的欄位,其內容值為國文、數學、英文的總和。 並利用觸發器(Trigger)或前端應用程式在相關分數(國文、數學、英文)變動時,自動維護總分的內容,以 保持資料的一致性。此方式即所謂的反正規化,可以增加查詢的效能,但也造成儲存空間的浪費,同時增 加了資料不一致的風險。所以使用反正規化前,必須仔細設計,避免相關的問題發生。 8.2 基本的資料型態 雖然 Oracle 資料庫支援許多種資料型態,但是正如”80-20”法則所發現的現象,絕大多數的表格中, 常用到的資料型態不脫文字、數字、日期等基本型態。以下便針對這些資料型態進行說明。 8.2.1 文字型態 此型態的欄位用來儲存文字資料,但是建立此種欄位前,需要注意資料寬度與編碼的選擇。 寬度 文字資料型態還可以依儲存空間分成:固定寬度(CHAR/NCAHR)與變動寬度 (VARCHAR2/NVARCHAR2/LONG/CLOB)兩種。 所謂固定寬度是說雖然輸入的欄位值小於該欄位的限制長度,但是實際儲存資料時,會先自動向右補足空 白後,才將欄位值的內容儲存到資料區塊中。這種方式較浪費空間,但是存取效率較變動寬度來得好,同 時也可以減少資料列遷移的發生。CHAR(x Byte|Char)表示此欄位最大只能存放 x Bytes(預設)或 x Characters 以資料庫字符集編碼的資料。Byte 表示 x 的單位是 Byte,Char 表示 x 的單位為 Character。 當一個 Character(符號)需要多個 Bytes 才能編碼時,CHAR(1 Byte)與 CHAR(1 Char)的實際儲存空間便 不相同,CHAR(1 Byte)只能容納 1 個 Byte 的資料,而 CHAR(1 Char)則可以容納 1 個 Character 的資 料,跟據 Character 由幾個 Bytes 所編碼決定,實際可以容納多少 Bytes(1/2/3/4)的資料。CHAR 的資 料欄位最大能夠存放 2000 Bytes 的資料。NCHAR 也是 2000 Bytes 的限制,不過 NCHAR(10)只有一 種選擇,即 10 CHAR,不能使用 10 Byte 的方式。 變動寬度則是當輸入的欄位值小於該欄位的限制長度,直接使用欄位值的內容儲存到資料區塊中,不會補 上空白,可以節省資料區塊的空間。VARCHAR2(x Byte|Char) 表示此欄位最大只能存放 x Bytes(預設) 或 x Characters 以資料庫字符集編碼的資料。Byte 表示 x 的單位是 Byte,Char 表示 x 的單位為 Character。當一個 Character(符號)需要 n 個 Bytes 才能編碼時,CHAR(1 Byte)與 CHAR(1 Char)的實 際儲存空間便不相同,CHAR(1 Byte)只能容納 1 個 Byte 的資料,而 CHAR(1 Char)則可以容納 1 個 Character 的資料,跟據 Character 由幾個 Bytes 所編碼決定,實際可以容納多少 Bytes(1/2/3/4)的資 料。 VARCHAR2 的資料欄位最大能夠存放 4000 Bytes 的資料。NVARCHAR2 也是 4000 Bytes,不 過 NVARCHAR2(10)只有一種選擇,即 10 CHAR,不能使用 10 Byte 的方式。而 LONG 可以儲存到 2G bytes 的資料。 編碼 文字型態的資料型態可依編碼方式分成:資料庫字符集(CHAR/VARCHAR2/CLOB/LONG)與國際字符 集(NCHAR/NVARCHAR2/NCLOB)兩種。資料庫中的文字資料都是透過字符集將符號轉換成數字後,才 存放到資料區塊中。透過不同的編碼集轉換,即便是相同的符號,也可能轉換成不同的數字。當然如果使 用錯誤的字符集,便可能無法正確地將資料區塊中的數字轉換為原本的符號。字符集的相關說明請參考 4.2.3。
  • 10. Chapter 8 Table Oracle Database 11g 資料庫管理入門 CHAR/VARCHAR2/LONG/CLOB 都用來儲存文字資料,所使用的編碼為資料庫字元集(Database Character Set),在建立資料庫時所指定的。通常不能再更改,不過在特殊情況下,可以更改。 從 Oracle8i 開始,新增以下三種資料型態:NCHAR/NVARCHAR2/NCLOB,也可以用來存放文字資料, 不過所使用的編碼方法為本國字元集(National Character Set)。自 Oracle9i 後只能由 Unicode 中的 UTF8(變動寬度)或 AL16UTF16(固定寬度)則一為之。 8.2.2 數字型態 數字型態欄位用來儲存數字資料,不過根據不同的數字資料,可以分成下列幾種型態。 NUMBER NUMBER(P,S)是最常見的數字型態,可存放的資料從 10^ -130 到 10^ 126 (不包含此數值),需要 1 到 22 Bytes 不等的儲存空間。 P 是 Precision(精確度)的縮寫,表示最多位數的有效十進位位數(digit),最多不能超過 38 個有效位數。 最大有效數位(Most Significant Digit)是數值的最左邊的非零位數,最低有效數字(Least Significant Digit)為數值的最右邊的位數。因此 123.45 這個數值中,1 是 MSD 而則是 LSD。 S 是 Scale 的縮寫,可使用範圍為-84 到 127。 Scale 為正數,表示從小數點到最低有效數字的位數。 Scale 為負數時,表示從最大有效數字到小數點的位數,但不包括最大有效數字。同時表示自小數點左邊 S 位數上四捨五入。 當 Scale 值大於 Precision 時,表示由小數點後的第 S 位數向左,不能有超過 P 個位數。同時自小數點後 的第 S 位開始四捨五入。 範例︰ 原始資料 資料型態 儲存結果 123.45 NUMBER 其實是宣告為 float 浮點數,P 為 38 123.45 123.45 NUMBER(3) 等同於 NUMBER(3,0) 123(小數點後四捨五入) 總精確度為 3 位,無小數點後位 數。 123.45 NUMBER(3,2) 無法儲存(3 表示最大精確度為 3 個 digit,且小數點後的 digit 佔 2 個), 原始資料共有 5 個 digit。 123.45 NUMBER(5,2) 123.45 123.45 NUMBER(6,2) 123.45 123.45 NUMBER(5,-1) 120(在小數點左邊的 1 位,進行四 捨五入,因為 3 不足 5,則捨去) 0.02345 NUMBER(4,5) 0.02345(小數點後第 5 位向左不能 有超過 4 個數字) 0.023456 NUMBER(4,5) 0.02346(小數點後第 5 位向左不能 有超過 4 個數字,並從小數點後第 5 位開始四捨五入,所以 56 進位成 6) 0.12345 NUMBER(4,5) 無法儲存(小數點後第 5 位向左不能 有超過 4 個數字,但 12345 共 5 個
  • 11. Chapter 8 Table Oracle Database 11g 資料庫管理入門 數字) INTEGER INTEGER 是 NUMBER 的子型態(SubType),其實等同 NUMBER(38,0),可以用來儲存整數,若數值有 小數,則會被四捨五入。如果需要限制數值的精確度,則建議使用 NUMBER(P,0),因為 INTEGER 的精 確度固定為 38。 --為方便觀察結果,往後的範例皆使用sys身份進行操作 SQL> CONNECT / AS SYSDBA SQL> CREATE TABLE frank.t1_int (a INTEGER); SQL> DESC frank.t1_int Name Null? Type ----------------------------------------------------------------- -------- ---------------------------------------- A NUMBER(38) SQL> CREATE TABLE frank.t2_int (a INTEGER); SQL> DESC frank.t2_int Name Null? Type ----------------------------------------------------------------- -------- ---------------------------------------- A NUMBER(38) SQL> INSERT INTO t1_int VALUES(1234567890123456789012345678901234567890); INSERT INTO t1 VALUES(1234567890123456789012345678901234567890) * ERROR at line 1: ORA-01438: value larger than specified precision allowed for this column /*1234567890123456789012345678901234567890共40位數*/ SQL> INSERT INTO t1_int VALUES(12345678901234567890123456789012345678); SQL> INSERT INTO t2_int VALUES(12345678901234567890123456789012345678.9); /*小數點後四捨五入*/ SQL> COMMIT; SQL> SELECT * FROM frank.t1_int; A --------------- 1.2346E+37 /*只是呈現的樣式如此,其實真的存入12345678901234567890123456789012345678的數值*/ SQL> SELECT * FROM frank.t2_int; A --------------- 1.2346E+37 /*只是呈現的樣式如此,其實真的存入12345678901234567890123456789012345679的數值,因為小數點 後四捨五入,切記*/ SQL> SELECT DUMP(a) FROM frank.t1_int; DUMP(A)
  • 12. Chapter 8 Table Oracle Database 11g 資料庫管理入門 -------------------------------------------------------------------------------------------------------------- Typ=2 Len=20: 211,13,35,57,79,91,13,35,57,79,91,13,35,57,79,91,13,35,57,79 SQL> SELECT DUMP(a) FROM frank.t2_int; DUMP(A) -------------------------------------------------------------------------------------------------------------- Typ=2 Len=20: 211,13,35,57,79,91,13,35,57,79,91,13,35,57,79,91,13,35,57,80 SQL> SELECT t1.a-t2.a “T1-T2” FROM frank.t1_int,frank.t2_int; T1-T2 -------- -1 SQL> SELECT t2.a-t1.a “T2-T1” FROM frank.t1_int,frank.t2_int; T2-T1 -------- 1 SQL> CREATE TABLE frank.t3_int(a INTEGER(10)); CREATE TABLE frank.t3_int(a INTEGER(10)) * ERROR at line 1: ORA-00907: missing right parenthesis /*INTEGER一定是NUMBER(38,0),不能設定精確度*/ SQL> CREATE TABLE frank.t3_int (a INTEGER); SQL> INSERT INTO frank.t3_int VALUES(123.4); SQL> INSERT INTO frank.t3_int VALUES(234.5); SQL> SELECT * FROM frank.t3_int; A ----------- 123 235 /*切記小數點後會四捨五入,而不是無條件捨去*/ FLOAT FLOAT 如同 INTEGER 一般,也是 NUMBER 的次型態,目前 FLOAT 的定義遵守的是 IEEE754 的標 準 。FLOAT 只能設定精確度(Precision)可由 1 到 126,但不能設定 Scale,但可以存入有小數的數值。 而且精確度並不是使用十進位呈現而是二進位。所以當 FLOAT(10)表示的是二進位精確度,需要轉成十 進位整數精確度,公式為二進位精確度*0.30103,若有小數則無條件進位。若要從十進位精確度轉成二 進位精確度,公式為十進位精確度*3.32193。 假設將 123.45 存入 FLOAT(5)的欄位中,則儲存後的值為 120。 實際的過程如下: 計算真正的精確度:FLOAT(5)的十進位精確度為 5*0.30103=1.50515,進位到最近的整數為 2。 數值轉換:123.45=1.2345*10^2 ,因為精確度不能超過 2 位數,同時進行四捨五入,所以數值變成 1.2*10^2=120。
  • 13. Chapter 8 Table Oracle Database 11g 資料庫管理入門 SQL> CREATE TABLE frank.t1_flt(a FLOAT(10,2)); CREATE TABLE frank.t1_flt(a FLOAT(10,2)) * ERROR at line 1: ORA-00907: missing right parenthesis /*FLOAT不能指定Scale*/ SQL> CREATE TABLE frank.t1_flt(a NUMBER,b FLOAT,c FLOAT(5),d FLOAT(9),e FLOAT(10)); SQL> DESC frank.t1_flt Name Null? Type ----------------------------------------------------------- -------- ---------------------------------------- A NUMBER B FLOAT(126) C FLOAT(5) D FLOAT(9) E FLOAT(10) /*FLOAT的最大二進位精確度為126*/ SQL> INSERT INTO frank.t1_flt VALUES(123.45,123.45,123.45,123.45,123.45); SQL> SELECT * FROM frank.t1_flt; A B C D E ------------- ------------ ----------- ---------- ---------- 123.45 123.45 120 123 123.5 /* FLOAT(126)的十進位精確度為126*0.30103=37.92978,進位後為38(十進位精確度)。 FLOAT(9)的十進位精確度為9*0.30103=2.70927,進位後為3。123.45=1.2345*10^2,因為數值有四捨五 入,所以4以後被捨棄,結果為123。 FLOAT(10)的十進位精確度為10*0.30103=3.0103,進位後為4。123.45=1.2345*10^2,因為數值有四捨 五入,導致4變成5,因此結果為123.5。*/ 8.2.3 日期型態 日期型態顧名思意是用來儲存日期資料,不過並不是使用一般所看到的格式(2009-01-01)直接存到資料 庫中,而是先將日期轉換為 Julian Day(儒略日,Oracle 採用天文學的定義),再將資料儲存到資料庫。 Julian Day 從西元前 4712 年 1 月 1 日中午開始為 1,以後每過一天就加上 1。所以如果將 2004-09- 15 改為 Julian Day 值則為 2453264。Oracle 資料庫中合法的日期範圍由 4712 BC 1 月 1 日到 9999 AD 12 月 31 日。 DATE DATE 是最常被使用的日期型態,它可以存放世紀、年、月、日、時、分、秒的資訊。固定需要 7 個 Bytes 空間儲存 DATE 型態的資料。 SQL> SELECT TO_CHAR(TO_DATE('2004-09-15','YYYY-MM-DD'),'J') julian_days FROM dual; JULIAN_ ----------- 2453264 SQL> SELECT TO_CHAR(TO_DATE('01-01-4712 BC','DD-MM-YYYY BC'),'J') julian_days FROM dual; JULIAN_ ----------- 0000001 SQL> SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS') FROM dual;
  • 14. Chapter 8 Table Oracle Database 11g 資料庫管理入門 TO_CHAR(SYSDATE,'YY -------------------------------- 2009-03-10 11:59:53 TIMESTAMP 從 Oracle9i 開始,Oracle 推出一種新的時間型態:TIMESTAMP。並且可以分成 TIMESTAMP、 TIMESTAMP WITH TIME ZONE 與 TIMESTAMP WITH LOCAL TIME ZONE 三種。 TIMESTAMP:可以儲存世紀、年、月、日、時、分、秒以及小數秒(最多可達小數點後 9 位)。需要 11 個 Bytes 空間儲存 TIMESTAMP 型態的資料。 TIMESTAMP WITH TIME ZONE:除了儲存 TIMESTAMP 的所有資訊外,另外還儲存時區(TIME ZONE) 資訊,所以需要多達 13 個 Bytes 的空間。 TIMESTAMP WITH LOCAL TIME ZONE:所欲儲存的 TIMESTAMP 資料先依資料庫端的時區,轉換為 資料庫端的 TIMESTAMP 格式,才儲存到資料庫中。當客戶端讀取該時間資訊時,自動將時間資料依客 戶端的時區資料轉換為 TIMESTAMP 格式呈現。需要 11 個 Bytes 的空間存放資料。 SQL> CREATE TABLE frank.t1_times(a TIMESTAMP,b TIMESTAMP WITH TIME ZONE,c TIMESTAM P WITH LOCAL TIME ZONE); SQL> INSERT INTO frank.t1_times VALUES(SYSTIMESTAMP,SYSTIMESTAMP,SYSTIMESTAMP); SQL> SELECT SESSIONTIMEZONE FROM dual; SESSIONTIMEZONE --------------------------------------------------------------------------- +08:00 /*目前SESSION的時區*/ SQL> SELECT * FROM frank.t1_times; ------------------------------------------------------------------ 12-MAR-09 02.23.49.029445 PM 12-MAR-09 02.23.49.029445 PM +08:00 12-MAR-09 02.23.49.029445 PM SQL> ALTER SESSION SET TIME_ZONE='-07:00'; /*將SESSION的時區改為-07:00*/ SQL> SELECT * FROM frank.t1_times; ----------------------------------------------------------------- 12-MAR-09 02.23.49.029445 PM 12-MAR-09 02.23.49.029445 PM +08:00 11-MAR-09 11.23.49.029445 PM /*TIMESTAMP WITH LOCAL TIME ZONE的時間會自動依客戶端的時區而調整*/ 8.2.4 LOB(Large Object) LOB 型態用來儲存大型資料。文字型態可以使用 CLOB(Character LOB)或 NCLOB(National Character LOB),依所使用的字元集分類。二進位資料則可以使用 BLOB(Binary LOB)或 BFILE(Binary FILE)。 CLOB、NCLOB 與 BLOB 最大可儲存(4Giga Bytes-1)*Block_size 的資料,而 BFILE 最大可達 4Giga Bytes。 文字大型物件(CLOB/NCLOB) 當資料大於 4000Bytes 時,一般的 VARCHAR2 或 NVARCHAR2 已經無法容納這麼大的資料。因此必 須使用 CLOB 或 NCLOB 來存放這些文字型態的資料。
  • 15. Chapter 8 Table Oracle Database 11g 資料庫管理入門 二進位大型物件(BLOB) 當二進位資料超過 2000Bytes 時,便不能使用 RAW 的型態儲存,必須改用 BLOB 的型態。必須使用 DBMS_LOB 來操作其內容,不能直接使用 SQL 指令操作。 二進位檔案(BFILE) BFILE 是用來儲存資料,與 CLOB/BLOB 不同的地方在於: 1.資料存放的位置不在資料庫中,而是在檔案系統的檔案中。所以 BFILE 欄位值只存放相對的檔案位置 (目錄物件名字與檔案名字),而不是真正的資料內容。BFILE 所使用的檔案格式可以為 GIF、JEPG、 JPG、MEPG、MPEG2、TEXT、AVI 或其他的格式。 2.因此 BFILE 的內容不能使用 SQL 指令修改,只能用在查詢操作。如果要更改 BFILE 內容,必須使用 正確儲存格式的編輯器修改。例如 AVI 格式需要使用影片編輯軟體修改其內容。 BFILE 所使用的檔案最大不能超做 4G Bytes。 8.2.5 資料列 id(Rowid) 資料列 id(rowid)是一個虛擬的欄位值,它並不存在於資料庫中,所以不會佔用資料列的空間。當每筆資 料列產生後,就有一個唯一的資料列 id 存在。資料列 id 用來表示資料列在資料庫的相對位置,而不是絕 對位置,只要使用資料列 id 可以直接找到包含該資料列的資料區塊。因此透過資料列 id 存取資料庫是存 取速度最快的方法,也是成本最低的方法。 然而資料列 id 的格式對人類來說相當難以記憶,因此資料庫才提供索引,將對人類較有意義的欄位值與 該資料列的資料列 id 組成索引項目儲存在索引。之後只要提供索引鍵欄位值,就可以透過索引取得該資 料列得資料列 id,使用資料列 id 讀取資料列。然而這種方法較直接使用資料列 id 來的慢,而且需要索引 的空間與維護成本。 資料列 id 分為實體資料列 id(Physical ROWID)與邏輯資料列 id(Logical ROWID)。邏輯資料列 id 用在索 引組織表格上的索引,而其他非索引組織表格上的索引則使用實體資料列 id。 Oracle Database 11g 可以使用的實體資料列 id 有下面三種︰受限制的資料列 id(Restricted rowid),延 伸的資料列 id(Extended rowid),通用的資料列 id(Universal rowid)。 受限的資料列 id(RESTRICTED ROWID) Oracle Database 7 所使用資料列 id 稱做受限的資料列 id,其顯示格式為 BBBBBB.RRRR.FFFF,如果 需要儲存則佔 6 Bytes(48 Bits)的空間。 其中 BBBBBB 為該資料列所在的資料區塊的號碼,需要佔 22 Bits 的空間,資料區塊號碼為資料檔的第 幾個資料區塊,而不是資料庫的第幾個資料區塊。RRRR 表示該資料列為資料區塊的第幾筆資料列,需要 佔 16 Bits 空間,資料列號碼由 0 開始。FFFF 為該資料列在資料庫的第幾個資料檔,需要佔 10 Bits 的 空間。因此可以得知 Oracle Database 7 的資料檔個數不能超過 2 10 -1 個(1023 個,因為 0 不能使用。), 當然也可以知道一個資料檔最多可以有 2 22 (400 萬)個資料區塊,每個資料區塊理論上可容納 2 16 (65536) 筆資料列。 當表格為非分區表格(Non-Partitioned Table)時,每個表格只有一個區段。因此平衡樹索引(B-tree Index) 的索引項目所使用資料列 id 為受限的資料列 id 即可。同時點陣圖索引(Bitmap Index)也使用受限的資料 列 id。 延伸的資料列 id(EXTENDED ROWID) Oracle Database 8 時新增一種新的資料列 id 的格式,稱做延伸的資料列 id(Extended Rowid),從名字 來看就知道是因應受限的資料列 id 的不足。這種資料列 id 的格式為 OOOOOO.FFF.BBBBBB.RRR,如 果需要儲存則需要 10 Bytes(80 Bits)的空間。其中用 OOOOOO 為該區段(Segment)的物件
  • 16. Chapter 8 Table Oracle Database 11g 資料庫管理入門 id(DATA_OBJECT_ID)佔 32 Bits,FFF 為表格空間的資料檔號碼(relative file number)佔 10 Bits, BBBBBB 為該資料列所在的資料區塊的號碼佔 22 Bits,RRRR 為該資料列為該資料區塊的第幾筆資料列 佔 16 Bits。 延伸的資料列 id 與受限的資料列 id 的差異,為延伸的資料列 id 多儲存了區段的物件 id。以及延伸的資料 列 id 所使用的檔案號碼為相對的檔案號碼,而受限的資料列 id 所使用的檔案號碼為絕對的檔案號碼。相 對的檔案號碼表示這個資料檔案為表格空間的第幾個資料檔,絕對的檔案號碼表示此資料檔為資料庫的第 幾個資料檔。不過在整個資料庫的資料檔個數在 1023 以下時,相對的檔案號碼與絕對的檔案號碼一樣。 因此當表格的區段分別存放在不同表格空間時,便可以使用區段的物件 id 得知所在的表格空間。所以在 分區表格上建立索引,索引項目所使用的資料列 id 就是延伸的資料列 id。因為在分區表格下,每個分區 都是一個區段,也就是說分區表格由多個區段組成。 延伸的資料列 id 以 Base 64 編碼方式呈現,也就是資料列 id 將由 A-Z,a-z,0-9,+,/等字元所組成。 以下為字元與數值的對應表。 字 元 A B C D E F G H I J K L M 數 值 0 1 2 3 4 5 6 7 8 9 10 11 12 字 元 N O P Q R S T U V W X Y Z 字 元 13 14 15 16 17 18 19 20 21 22 23 24 25 符 號 a b c d e f g h i j k l m 字 元 26 27 28 29 30 31 32 33 34 35 36 37 38 字 元 n o p q r s t u v w x y z 數 值 39 40 41 42 43 44 45 46 47 48 49 50 51 字 元 0 1 2 3 4 5 6 7 8 9 10 + / 數 值 52 53 54 55 56 57 58 59 60 61 62 63 64
  • 17. Chapter 8 Table Oracle Database 11g 資料庫管理入門 邏輯資料列 id(Logical ROWID) 邏輯資料列 id 用在索引組織表格(Index Organization Index)上的索引,因為在索引組織表格上的資料列 並不會永遠儲存在同一個位置,資料列將隨主鍵值而更換儲存位置。因此在索引組織表格上建立索引時, 使用邏輯資料列 id。邏輯資料列 id 由實體猜測位置(Physical Guess DBA)與主鍵值(Primary Key)所組成。 實體猜測位置是建立索引時,該筆資料列所在的資料區塊位置。 通用的資料列 id(UNIVERSAL ROWID) 通用的資料列 id 是 Oracle Database 8i 開始使用的資料列 id 型態,可以用來儲存實體資料列 id、邏輯資 料列 id 與外部表格(含非 Oracle 資料表)的資料列 id。通用的資料列 id 最大可達 4000 Bytes。 8.2.6 虛擬欄位 由 Oracle Database 11g 開始,可以宣告一種欄位型態:虛擬欄位,這種欄位並沒有真正的消耗儲存空 間,只有存在於表格定義中。當此欄位被查詢時,才會使用欄位定義的公式計算欄位值。欄位定義的公式 可以包括任何合法的運算以及函數。
  • 18. Chapter 8 Table Oracle Database 11g 資料庫管理入門 SQL> CREATE TABLE frank.t1_vir 2 (a NUMBER,b NUMBER,c NUMBER GENERATED ALWAYS AS (a+b) VIRTUAL); /*GENERATED ALWAYS是為語法容易看懂而存在,VIRTUAL也是相同用途。所以可以直接使用c NUMBE R AS (a+b)即可*/ SQL> DESC frank.t1_vir /*這裡看不出來,是否有使用虛擬欄位*/ Name Null? Type --------------------------------------------------------- ------ ------------- A NUMBER B NUMBER C NUMBER SQL> SELECT column_name,data_type,data_default FROM dba_tab_columns 2> WHERE OWNER=’FRANK’ AND table_name='T1_VIR' ; COLUMN_NAM DATA_TYPE DATA_DEFAULT ------------------- ----------------- -------------------------- A NUMBER B NUMBER C NUMBER "A"+"B" /*欄位公式*/ SQL> INSERT INTO frank.t1_vir VALUES(1,2,3); /*不能直接Insert/Update虛擬欄位的內容*/ INSERT INTO frank.t1_vir VALUES(1,2,3) * ERROR at line 1: ORA-54013: INSERT operation disallowed on virtual columns SQL> INSERT INTO frank.t1_vir VALUES(1,2); INSERT INTO frank.t1_vir VALUES(1,2) * ERROR at line 1: ORA-00947: not enough values SQL> INSERT INTO frank.t1_vir(a,b) VALUES(1,2); /*必須如此才能新增成功*/ ---或 INSERT INTO frank.t1_vir VALUES(1,2,DEFAULT); 1 row created. SQL> SELECT * FROM frank.t1_vir; A B C ----------- ---------- ---------- 1 2 3 /*找出row真正存放的位置*/ SQL> SELECT dbms_rowid.rowid_relative_fno(rowid) file#, 2 dbms_rowid.rowid_block_number(rowid) block# 3 FROM frank.t1_vir WHERE a=1 AND b=2 AND c=3; FILE# BLOCK# ------------ ----------- 1 40378 --將Data Block內容dump到user tracefile SQL> ALTER SYSTEM DUMP DATAFILE 1 BLOCK 40378;
  • 19. Chapter 8 Table Oracle Database 11g 資料庫管理入門 SQL> SHOW PARAMETER user_dump_dest /*確認User tracefile的位置*/ NAME TYPE VALUE ----------------------------- --------- ------------------------------------------------------- user_dump_dest string /u03/diag/diag/rdbms/ora11g/ora11g/trace /*找到伺服器處理作業(Server Process)在作業系統行程的號碼(OS Process ID)*/ SQL> SELECT spid FROM v$process 2 WHERE addr=(SELECT paddr FROM v$session 3 WHERE sid=(SELECT DISTINCT sid FROM v$mystat)); SPID -------- 5000 --這個行程號碼可能依環境不同而不同 SQL> !cat /u03/diag/diag/rdbms/ora11g/ora11g/trace/ora11g_ora_5000.trc --tracefile格式為SID_ora_OSPID.trc --從Data Block的內容來看,可以證明虛擬欄位-C,並未佔有任何空間。 block_row_dump: tab 0, row 0, @0x1f85 tl: 9 fb: --H-FL-- lb: 0x1 cc: 2 col 0: [ 2] c1 02 /*A欄位*/ col 1: [ 2] c1 03 /*B欄位*/ end_of_block_dump End dump data blocks tsn: 0 file#: 1 minblk 40378 maxblk 40378 使用者自行定義函數(User Defined Function) 當虛擬欄位用到使用者自行定義函數(User Defined Function)時,必須確定函數是明確性(Deterministic), 即只要輸入相同的參數值,函數就一定回傳相同的結果。 SQL> CREATE OR REPLACE minus_10(x NUMBER) RETURN NUMBER 2 IS 3 BEGIN 4 RETURN x-10; 5 END; 6 / SQL> CREATE TABLE frank.t2 (a NUMBER,b NUMBER,c NUMBER AS (minus_10(a+b)) VIRTUA L); CREATE TABLE frank.t2 (a NUMBER,b NUMBER,c NUMBER AS (minus_10(a+b)) VIRTUAL) * ERROR at line 1: ORA-30553: The function is not deterministic SQL> CREATE OR REPLACE minus_10(x NUMBER) RETURN NUMBER DETERMINISTIC 2 IS 3 BEGIN 4 RETURN x-10; 5 END; 6 / SQL> CREATE TABLE frank.t2_vir (a NUMBER,b NUMBER,c NUMBER AS (minus_10(a+b)) VIRT UAL);
  • 20. Chapter 8 Table Oracle Database 11g 資料庫管理入門 虛擬欄位的操作 虛擬欄位在 Oracle Database 11g 中,被當作一般的欄位,所以除了不能直接新增、異動其內容外,其 餘的操作如:當做主鍵、建立索引等都可以正常使用。 SQL> CREATE INDEX frank.t1_vir_c_idx ON t1_vir(c); SQL> SELECT index_name,index_type FROM dba_indexes 2 WHERE owner=’FRANK’ AND table_name='T1_VIR'; INDEX_NAME INDEX_TYPE ------------------------------- -------------------------------------- T1_VIR_C_IDX FUNCTION-BASED NORMAL /*從INDEX_TYPE可以得知,當建立索引在虛擬欄位上時,所建立的索引為Function-Based形態*/ SQL> ALTER TABLE frank.t1_vir ADD CONSTRAINT t1_vir_c_pk PRIMARY KEY(c); / 可以當作Primary KEY*/ SQL> EXECUTE dbms_stats.gather_table_stats('FRANK','T1_VIR'); /*收集統計值*/ /*虛擬欄位也可以當作分區欄位,這種分區方式稱為Virtual Column-Based Partitioning*/ SQL> CREATE TABLE frank.t3_vir 2 (a NUMBER,b NUMBER,c NUMBER AS (a+b+100) VIRTUAL) 3 PARTITION BY RANGE (c) 4 (PARTITION p1 VALUES LESS THAN(150), 5 PARTITION p2 VALUES LESS THAN(250), 6 PARTITION p3 VALUES LESS THAN(350)); 虛擬欄位的使用限制 目前虛擬欄位在使用上,還存在著一些限制: 1.僅適用在 Heap Organized Table 上,還不能用在 Index-Organized、Cluster、External、 Temporary 以及 Object 等表格上。 2.虛擬欄位不能參考其他的虛擬欄位,只能參考同一個表格中的真實欄位。 3.當使用函數時,此函數必須宣告為 Deterministic 以及回傳的資料型態必須為 Scalar。 4.虛擬欄位的資料型態不能為 PL/SQL 的資料形態、User Defined Type、LOB 以及 Long Raw 等型態。 8.3 表格的種類 表格用來儲存資料,根據不同型態的資料與存取的樣式,資料庫管理人員可以選擇不同型態的表格,來達 到最佳的儲存空間與存取效率。一般常見的表格型態為堆集組織表格(Heap Table),當然還可以依據不同 的需求建立如:分區表格(Partitioned Table)、索引組織表格(Index Organized Table)、叢集表格 (Cluster)、暫時表格(Temporary Table)與外部表格(External Table)等。 8.3.1 堆集組織表格(Heap Organized Table) 通常資料庫中最常見的表格型態就是堆集表格(Heap Table)也可以稱作一般表格(Regular Table)。當使用 這種表格時,資料庫管理人員無法控制資料列(Row)的位置,資料列根據可用區塊串列(Freelists)或自動 區段空間管理(ASSM)機制決定存放的資料區塊,也可以說在此種表格中資料是無特別的順序。當建立表 格時,基本上需要知道這個表格將放在哪個綱要(Schema)、哪個表格空間。當然表格的名字與欄位名稱 與資料型態也不可以不知道。 建立表格前,必須確定建立者擁有相關的權限以及表格空間配額(Quota)。如果是將表格建立在自己的綱 要下,僅需要 CREATE TABLE 的系統權限以及足夠的表格空間配額即可。若要將表格建立在其他的綱 要下,則需要 CREATE ANY TABLE 的系統權限以及表格擁有者必須有足夠的表格空間配額。
  • 21. Chapter 8 Table Oracle Database 11g 資料庫管理入門 綱要物件(Schema Object)的命名規則 所謂的綱要物件是指那些可以放在綱要中的物件,例如:表格、索引(Index)、視圖(View)、限制 (Constraint)、程序(Procedure)、函數(Function)、套件(Package)、觸發器(Trigger)等都是常見的綱要 物件。綱要其實是一個邏輯的容器,包含著屬於與綱要相同名字的使用者的所有物件的集合。因此當將一 個表格在 FRANK 的綱要下時,表示這個表格是屬於 FRANK 這個使用者擁有的物件。然而眾多的物件需 要許多不同的名字,以正確的辨別物件。因此需要一個命名規則來幫助資料庫管理人員記憶與方便管理這 些綱要物件。 物件名稱必須在 30 個 Bytes 之內。不過有少數例外,例如:資料庫名字只能有 8 個 Bytes,但是資料庫 連結(Database Link)可以多達 128 個 Bytes。 可以使用的字元僅限於 A 到 Z 或 a 到 z 的大小寫英文字母與 0 到 9 的阿拉伯數字,加上#、_、$這三 個特殊符號。若是資料庫連接還可以使用 . 與@兩種特殊字元。不過若在名字前後加上雙引號,則任何字 元都可使用,甚至空白也可以。 物件名稱不能使用資料庫的保留字,如 TABLE、INDEX 等。但若使用雙引號則不受此限。 物件名稱要以英文字母開頭,若使用雙引號不受此限。 物件名稱並沒有大小寫的差別,因為 Oracle 都會將物件名稱轉成大寫,才存到資料辭典。如果使用雙引 號則會保留原來的大小寫格式。 當使用雙引號包裹物件名稱時,未來使用該物件時,必須也要使用雙引號才能正確呼叫該物件。所以不建 議使用雙引號。 在同一個綱要下,以下幾種物件(TABLE/VIEW/SEQUENCE/Private SYNONYM/PROCEDURE/FUNCTION/PACKAGE/MATERIALIZED VIEW/User-Defined Type)不能 使用相同的名稱,因為他們位於相同的命名空間(NameSpace)。但是不同綱要屬於不同的命名空間,所 以可以在 FRANK 綱要與 SCOTT 綱要中,都存在一個叫做 EMP 的表格。 以下的綱要物件(INDEX/CONSTRAINT/CLUSTER/TRIGGER/Private Database Link/DIMENSION)擁 有自己的命名空間,所以即便是同一個綱要中已有一個 EMP 表格,還是可以建立一個叫做 EMP 的索引 或限制。不過同一個命名空間中,不能有相同名稱的物件存在。 表格範例 當建立一個表格之前,首先要確定幾件事。 擁有 CREATE TABLE 權限或 CREATE ANY TABLE(將表格放到別人的綱要中)。 表格所在表格空間尚有足夠的配額。 此外還要決定表格所在的綱要、表格名稱、欄位名稱及欄位的資料型態與長度,而一個表格中最多可以 1000 個欄位。以下是建立堆集組織表格(Heap Organized Table)的範例。 SQL> CONNECT / AS SYSDBA SQL> CREATE TABLE frank.t1 --schema.table_name,表示此表格要放在哪個綱要下。 2 (a NUMBER(4), --宣告欄位名稱與資料型態 3 b VARCHAR2(10), 4 c DATE DEFAULT SYSDATE) --設定欄位的預設值,預設值的資料型態必須與欄位相同。 5 ORGANIZATION HEAP --建立堆集組織表格,可以不用強調,因為堆疊表格為預設值。 6 TABLESPACE users; --此表格的區段(Segment)所放置的位置。 可以從DBA_TABLES/ALL_TABLES/USER_TABLES中查詢相關的資訊 SQL> SELECT owner,table_name,tablespace_name 2 FROM dba_tables 3 WHERE table_name='t1' and owner='frank'; no rows selected --表格名稱會轉換成大寫後,才存入資料辭典。
  • 22. Chapter 8 Table Oracle Database 11g 資料庫管理入門 SQL> SELECT owner,table_name,tablespace_name 2 FROM dba_tables 3 WHERE table_name='T1' and OWNER='FRANK'; OWNER TABLE_NAME TABLESPACE_NAME ------------------------------ ----------------------------------- ------------------------------ FRANK T1 USERS SQL> SELECT object_id,data_object_id,object_name,object_type 2 FROM dba_objects 3 WHERE owner='FRANK' and object_name='T1'; OBJECT_ID DATA_OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------------- ------------------------- ----------------------- ------------------- 84547 84547 T1 TABLE /*在Oracle資料庫中每個物件都有一個獨一的物件ID(Object_Id),用來辨識物件,同時如果該物件是區段(se gment)物件時,也會有一個資料物件ID(Data_Object_Id)用來辨識其所擁有的區段*/ SQL> SELECT segment_type,tablespace_name,header_file,header_block,bytes,blocks 2 FROM dba_segments 3 WHERE owner='FRANK' and segment_name='T1'; SEGMENT_TYPE TABLESPACE_NAME HEADER_FILE HEADER_BLOCK BYTES BLOCKS ----------------------- ------------------------------ -------------------- ------------------------- ------------- --------------- TABLE USERS 4 889 65536 8 /*每個區段都可有DBA_SEGMENTS/ALL_SEGMENTS/USER_SEGMENTS中查知其相關的資訊,例如:S EGMENT_TYPE可以得知該區段的型態為TABLE或INDEX等。 TABLESPACE_NAME則可以知道該區段所 使用的表格空間為何?而HEADER_FILE與HEADER_BLOCK則可以得到SEGMENT_HEADER所在的位 置。EXTENTS則顯示目前區段所被配置的擴充區段個數。BYTES與BLOCKS則顯示目前區段的大小,分別 以Bytes或Block個數呈現。*/ SQL> SELECT extent_id,file_id,block_id,blocks,bytes 2 FROM dba_extents 3 WHERE owner='FRANK' and segment_name='T1' and tablespace_name='USERS'; EXTENT_ID FILE_ID BLOCK_ID BLOCKS BYTES ----------------- ------------- -------------- ------------- ---------- 0 4 889 8 65536 /*此外也可以由DBA_EXTENTS/ALL_EXTENTS/USERS_EXTENTS中查知區段與擴充區塊的關係,例如: EXTENT_ID表示該擴充區塊是區段中的第幾個擴充區塊。FILE_ID則表示該擴充區塊是由那個資料檔中取得 相關的資料區塊。BLOCK_ID表示該擴充區塊是由資料檔的第幾個資料區塊開始,BLOCKS則表示該擴充區 塊為幾個連續的資料區塊組成。*/
  • 24. Chapter 8 Table Oracle Database 11g 資料庫管理入門 STORAGE 子句 建立表格時,可以利用 STORAGE 子句設定表格的擴充區塊(Extent)參數。一個表格直接限制其大小, 但是可以透過擴充區塊的設定,間接限制其大小。若沒有設定 STORAGE 參數,則會依照此表格所在的 表格空間設定值設定相關的 STORAGE 參數。 SQL> CREATE TABLE frank.t2 2 (a NUMBER,b VARCHAR2(10),c DATE) 3 TABLESPACE users 4 STORAGE(INITIAL 1M NEXT 1M PCTINCREASE 0 MINEXTENTS 1 MAXEXTENTS 100); /* INITIAL 1M設定第一個EXTENT的大小。 NEXT 1M指定第二個EXTENT的大小。 PCTINCREASE 0表示第三個EXTENT的大小為上一個EXTENT(即第二個)*(1+pctincrease/100),並以此 類推,第四個的大小為第三個的大小*(1+PCTINCREASE/100)。 MINEXTENTS表示建立此區段時,至少要有配置幾個擴充區塊。 MAXEXTENTS表示此區段,最多不能超過幾個擴充區塊。*/ 從Oracle11g之後可以使用一個新的STORAGE參數:MAXSIZE,直接指定這個表格的大小,不需要辛苦的 計算EXTENT的大小與個數。 SQL> CREATE TABLE frank.t2 2 (a NUMBER,b VARCHAR2(10),c DATE) 3 TABLESPACE users 4 STORAGE(MAXSIZE 10M); /*這個表格的總空間不能超過10M*/
  • 25. Chapter 8 Table Oracle Database 11g 資料庫管理入門 8.3.2 暫時表格(Temporary Table) 一般的表格建立後,都會有相對的區段(Segment)產生,而且這個區段必須指定所在的表格空間。然而 Oracle8i 後新增一種表格型態:暫時表格(Temporary Table),此種表格不需事先建立區段,而是當每個 階段作業(Session)第一次將資料新增(INSERT)到該暫時表格時,才會在該階段作業所使用的暫時表格空 間或暫時表格事先設定的暫時表格空間上,建立一個暫時區段。因此一個暫時表格可能會有多個區段同時 存在,但是每個階段作業僅能存取自己產生的暫時區段,所以暫時區段不會被其他階段作業所存取。因此 當暫時表格進行異動時,不需要使用鎖定(Lock)以避免同時異動,因為沒有其他階段作業可以異動其內容, 也不用擔心暫時表格的內容被其他階段作業看到。如此可以減少資料異動時的操作成本,也提供資料私密 性的功能。同時暫時表格上可以建立索引、限制與授與物件權限等,也可以正常的執行 DDL 指令(除 Truncate 外)。 資料保存時限 ON COMMIT DELETE ROWS: ON COMMIT DELETE ROWS 是暫時表格的預設參數,表示暫時表格中的資料僅在交易(Transaction)過 程中有效,當交易結束(COMMIT)時,暫時表格的暫時區段將自動被截斷(TRUNCATE)。 ON COMMIT PRESERVE ROWS: ON COMMIT PRESERVE ROWS 表示,暫時表格的內容,可以跨越交易而存在,不過當該階段作業結束 時,暫時表格的暫時區段將會隨著階段作業結束而被丟棄,暫時表格中的資料自然也隨之丟棄。 SQL> CREATE GLOBAL TEMPORARY TABLE frank.t3 2 (a NUMBER,b VARCHAR2(10)); /*由於沒有指定所在的表格空間,因此暫時表格的暫時區段將會產生在使用者FRANK的暫時表格空間中。 而資料保存時限為ON COMMIT DELETE ROWS*/
  • 26. Chapter 8 Table Oracle Database 11g 資料庫管理入門 SQL> CREATE GLOBAL TEMPORARY TABLE frank.t4 2 (a NUMBER,b VARCHAR2(10)) 3 TABLESPACE tempfrank; /*此暫時表格的暫時區段將會產生在暫時表格空間TEMPFRANK中。 而資料保存時限為ON COMMIT DELETE ROWS*/ SQL> CREATE GLOBAL TEMPORARY TABLE frank.t5 2 (a NUMBER,b VARCHAR2(10)) 3 ON COMMIT PRESERVE ROWS; /*由於沒有指定所在的表格空間,因此暫時表格的暫時區段將會產生在使用者FRANK的暫時表格空間中。 而資料保存時限為ON COMMIT PRESERVE ROWS*/ SQL> SELECT table_name,tablespace_name,duration 2 FROM dba_tables 3 WHERE owner='FRANK' AND table_name IN ('T3','T4','T5'); TABLE_NAME TABLESPACE_NAME DURATION ------------------------------ ----------------------------------- ---------------------------- T5 SYS$SESSION T4 TEMPFRANK SYS$TRANSACTION T3 SYS$TRANSACTION SQL> COMMIT; /*結束交易*/ SQL> SELECT * FROM frank.t3; no rows selected /*因為暫時表格中尚未有任何資料*/ SQL> SELECT * FROM frank.t5; no rows selected /*因為暫時表格中尚未有任何資料*/ SQL> INSERT INTO frank.t3 VALUES(1,'A'); SQL> INSERT INTO frank.t5 VALUES(1,'A'); SQL> SELECT * FROM frank.t3; A B ---------- ---------- 1 A SQL> SELECT * FROM frank.t5; A B ---------- ---------- 1 A SQL> COMMIT; /*結束交易*/ SQL> SELECT * FROM frank.t3; no rows selected /*因為frank.t3的保存期限為交易期間,所以當交易結束後,暫時表格也會被截斷*/ SQL> SELECT * FROM frank.t5; A B ---------- ----------
  • 27. Chapter 8 Table Oracle Database 11g 資料庫管理入門 1 A /*因為frank.t5的保存期限為階段作業期間,所以當交易結束後,暫時表格不會被截斷*/ SQL> exit /*結束此階段作業,此時frank.t5的暫時區段將為隨著階段作業的結束,而被丟棄*/ [oracle@ELinux ~]$ sqlplus frank/oracle SQL> SELECT * FROM frank.t5; no rows selected /*在此階段作業中,frank.t5尚未被新增任何資料,所以連暫時區段都還沒有產生*/ 8.3.3 外部表格(External Table) 外部表格用來存取資料庫外的文字檔(Text File)或 Oracle 專屬格式檔內容。因此建立外部表格時,不會 產生區段、擴充區塊、資料區塊等儲存結構,只有表格相關的定義存放在資料辭典中。當存取外部表格時, 才透過相關設定從文字檔或 Oracle 專屬格式檔案中取得資料。同時因為資料存放在資料庫之外,所以僅 供查詢(Select),不能對外部表格內容進行異動(Insert/Update/Delete)。 目錄物件(Directory) 自 Oracle Database 9i 開始,Oracle 資料庫若需要存取檔案系統時,必須使用目錄物件以相對路徑的方 式存取檔案,以增加資料庫安全性。所以使用外部表格前,需要先建立目錄物件,並授權資料庫的使用者 可以讀寫該目錄物件下的檔案。 [oracle@ELinux ~]$ pwd /home/oracle [oracle@ELinux ~]$ mkdir external_demo [oracle@ELinux ~]$ sqlplus / as sysdba SQL> CREATE DIRECTORY external_demo AS '/home/oracle/external_demo'; /*若在UNIX環境下,請注意大小寫差異,因為UNIX的目錄與檔案名稱大小寫視作不同目錄或檔案。 SQL> GRANT READ,WRITE ON DIRECTORY external_demo TO frank; /*授予frank可以讀、寫目錄物件下的檔案。 文字檔 從 Oracle Database 9i 開始,資料庫管理者便可以利用外部表格將當文字檔當作資料來源。此時需要使 用 ORACLE_LOADER 這個存取界面來讀取文字檔,其實 ORACLE_LOADER 透過 SQL*LOADER 的 幫助,因此相關的存取設定都與 SQL*LOADER 類似。ACCESS PARAMETERS 為整個外部表格定義中 最重要的一部份,包含如何將文字檔的資料對應到外部表格。其中 RECORDS DELIMITED 用來設定如 何將文字檔資料轉成一筆 Record,Record 為 Field 所組成的結構。FIELDS TERMINATED BY 決定如 何將 Record 分割成 Field。一般常見的是 FIELDS TERMINATED BY `,’即使用逗號將 Record 分割 成多個 Field。或者是 FIELDS TERMINATED BY WHITESPACE 則是使用空白來分割 Field。 [oracle@ELinux ~]$ cat /home/oracle/external_demo/emp.txt --測試範例文字檔 100,Frank,1999-05-15,15000 101,Linda,2004-09-16,20000 102,Gigi,2005-02-23,7800 103,Wilson,2007-09-06,10000 /*100,Frank,1999-05-15,15000為一個Record,Frank則為一個Field,Field之間依逗號為間隔*/ [oracle@ELinux ~]$ sqlplus frank/oracle SQL> CREATE TABLE emp_ext 2 (empid NUMBER(4), 3 ename VARCHAR2(10), 4 hire_date DATE, 5 salary NUMBER(6))
  • 28. Chapter 8 Table Oracle Database 11g 資料庫管理入門 6 ORGANIZATION EXTERNAL --宣告這是個外部表格 7 (TYPE ORACLE_LOADER --資料來源是文字檔,所以使用ORACLE_LOADER 8 DEFAULT DIRECTORY external_demo --文字檔所在目錄的相對目錄物件 9 ACCESS PARAMETERS --如何切割文字檔中的資料,以及如何對應到表格 10 (RECORDS DELIMITED BY NEWLINE --每筆Record以NEWLINE符號分隔,Record可視為Row 11 FIELDS TERMINATED BY ',' --每個Field以逗號為間隔 12 (empid,ename,hire_date DATE MASK 'YYYY-MM-DD',salary) --DATE MASK設定日期格式 13 ) 14 LOCATION('emp.txt') --文字檔的名字 15 )REJECT LIMIT UNLIMITED --發生幾次錯誤後,讀取動作將會中斷。UNLIMITED為無限制 16 ; SQL> DESC emp_ext Name Null? Type ----------------------------------------------------- ----------- ---------------------------------------- EMPID NUMBER(4) ENAME VARCHAR2(10) HIRE_DATE DATE SALARY NUMBER(6) SQL> SELECT * FROM emp_ext; EMPID ENAME HIRE_DATE SALARY ---------- -------------------- ---------------- ------------ 100 Frank 15-MAY-99 15000 101 Linda 16-SEP-04 20000 102 Gigi 23-FEB-05 7800 103 Wilson 06-SEP-07 10000 SQL> SELECT object_id,data_object_id,object_type FROM user_objects 2 WHERE object_name='EMP_EXT'; OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE ---------------- ------------------------- ------------------- 89052 TABLE --沒有data_object_id表示這個物件沒有相對的區段。 SQL> SELECT extent_id,blocks,bytes FROM user_extents WHERE segment_name='EMP_EXT'; no rows selected --真的沒有此區段存在 /*除使用符號分割Field外,也可以使用固定寬度的方式分割Field*/ [oracle@ELinux ~]$ cat /home/oracle/external_demo/emp1.txt 100 Frank 1999-05-15 15000 101 Linda 2004-09-16 20000 102 Gigi 2005-02-23 7800 103 Wilson 2007-09-06 10000 [oracle@ELinux ~]$ sqlplus frank/oracle SQL> CREATE TABLE emp1_ext 2 (empid NUMBER(4), 3 ename VARCHAR2(10), 4 hire_date DATE, 5 salary NUMBER(6)) 6 ORGANIZATION EXTERNAL 7 (TYPE ORACLE_LOADER 8 DEFAULT DIRECTORY external_ 9 ACCESS PARAMETERS 10 (RECORDS DELIMITED BY
  • 29. Chapter 8 Table Oracle Database 11g 資料庫管理入門 11 FIELDS(empid(1:4),ename(6:15),hire_date(17:26) DATE mask 'YYYY-MM-DD',salary(28:33)) 12 ) 13 LOCATION('emp1.txt') 14 )REJECT LIMIT UNLIMITED 15 ; /*使用固定寬度方式切割Record為Field,並對應到Column*/ SQL> SELECT * FROM emp_ext; EMPID ENAME HIRE_DATE SALARY ---------- -------------------- ---------------- ------------ 100 Frank 15-MAY-99 15000 101 Linda 16-SEP-04 20000 102 Gigi 23-FEB-05 7800 103 Wilson 06-SEP-07 10000 SQL> SELECT table_name,type_name FROM user_external_tables; --查詢有哪些外部表格 TABLE_NAME TYPE_NAME ------------------------------ ------------------------------ EMP_EXT ORACLE_LOADER EMP1_EXT ORACLE_LOADER Oracle 專屬格式檔 自 Oracle Database 10g 後,Oracle 增加一種新的外部表格格式,使用 Oracle 專屬格式檔案,而不是文 字檔。這種檔案是二進位格式,不過其中資訊是以 XML 格式存放。這種外部表格建立方式有兩種: UNLOAD(卸載)與 LOAD(載入)。 卸載:使用 CTAS(Create Table As Select)語法建立一個新的外部表格,為何稱為卸載?原因為這個外 部表格的資料來源為子查詢(SubQuery),而將資料存放到某個 Oracle 專屬格式檔案中,而不是資料庫中 的另一個表格。 SQL> DESC emp Name Null? Type ----------------------------------------------------- ----------- ---------------------------------------- EMPID NUMBER(3) ENAME VARCHAR2(20) HIRE_DATE DATE SALARY NUMBER(7) SQL> SELECT * FROM emp; EMPID ENAME HIRE_DATE SALARY ---------- -------------------- ---------------- ------------ 100 Frank 15-MAY-99 15000 101 Linda 16-SEP-04 20000 102 Gigi 23-FEB-05 7800 103 Wilson 06-SEP-07 10000 SQL> SELECT object_id,data_object_id,object_type FROM user_objects WHERE object_name='EMP'; OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE ---------------- ------------------------- ------------------- 89054 89054 TABLE --data_object_id不是空值,表示這是一個標準表格
  • 30. Chapter 8 Table Oracle Database 11g 資料庫管理入門 SQL> SELECT extent_id,blocks,bytes FROM user_extents WHERE segment_name='EMP'; EXTENT_ID BLOCKS BYTES ---------------- ------------ ---------- 0 8 65536 --此表格目前有一個擴充區塊 SQL> CREATE TABLE emp2_ext 2 ORGANIZATION EXTERNAL --宣告為外部表格 3 (TYPE ORACLE_DATAPUMP --檔案格式為Oracle專屬格式 4 DEFAULT DIRECTORY external_demo --使用external_demo這個目錄物件 5 LOCATION('emp2.dmp') --檔案的名字 6 ) 7 AS 8 SELECT * FROM emp; --卸載的資料來源 SQL> DESC emp2_ext Name Null? Type ----------------------------------------------------- ----------- ---------------------------------------- EMPID NUMBER(3) ENAME VARCHAR2(20) HIRE_DATE DATE SALARY NUMBER(7) SQL> SELECT * FROM emp2_ext; EMPID ENAME HIRE_DATE SALARY ---------- -------------------- ---------------- ------------ 100 Frank 15-MAY-99 15000 101 Linda 16-SEP-04 20000 102 Gigi 23-FEB-05 7800 103 Wilson 06-SEP-07 10000 SQL> SELECT object_id,data_object_id,object_type FROM user_objects 2 WHERE object_name='EMP2_EXT'; OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE ---------------- ------------------------- ------------------- 89055 TABLE --沒有data_object_id SQL> SELECT default_directory_name,type_name FROM user_external_tables 2 WHERE table_name='EMP2_EXT'; DEFAULT_DIRECTORY_NAME TYPE_NAME ----------------------------------------- ------------------------------ EXTERNAL_DEMO ORACLE_DATAPUMP --證實emp2_ext為外部表格,並且使用ORACLE_DATAPUMP界面存取檔案 SQL> SELECT directory_name,location FROM user_external_locations 2 WHERE table_name='EMP2_EXT'; --卸載後產生的檔案位置與名字 DIRECTORY_NAME LOCATION ---------------------------- ----------------- EXTERNAL_DEMO emp2.dmp SQL> SELECT directory_path FROM dba_directories WHERE directory_name='EXTERNAL_DEMO'; DIRECTORY_PATH --------------------------------------------------------------------------------------------------------------
  • 31. Chapter 8 Table Oracle Database 11g 資料庫管理入門 /home/oracle/external_demo --檔案系統上真實目錄 SQL> !ls -l /home/oracle/external_demo/emp2.dmp -rw-r----- 1 oracle oinstall 12288 Mar 27 17:00 /home/oracle/external_demo/emp2.dmp --建立外部表格所產生出的Oracle專屬格式檔案,其中存放著emp2_ext表格的內容 載入:載入為建立一個外部表格,能夠對應到之前產生 Oracle 專屬格式檔案的內容,讓資料庫的使用者 不須將檔案內容載入資料庫,即可透過外部表格查詢其內容。 [oracle@ELinux ~]$ pwd /home/oracle [oracle@ELinux ~]$ mkdir ext_dir [oracle@ELinux ~]$ cp /home/oracle/external_demo/emp2.dmp /home/oracle/ext_dir/emp3.dmp [oracle@ELinux ~]$ ls -l /home/oracle/ext_dir/emp3.dmp -rw-r----- 1 oracle oinstall 12288 3月 27 17:25 /home/oracle/ext_dir/emp3.dmp [oracle@ELinux ~]$ sqlplus / as sysdba --因為要建立新的目錄物件 SQL> CREATE DIRECTORY ext_dir AS '/home/oracle/ext_dir'; SQL> GRANT READ,WRITE ON DIRECTORY ext_dir TO frank; --授權讓Frank可以讀寫ext_dir目錄物件 SQL> CONNECT frank/oracle --切換身份為frank SQL> CREATE TABLE emp3_ext 2 (empid NUMBER(4), 3 ename VARCHAR2(10), 4 hire_date DATE, 5 salary NUMBER(6)) 6 ORGANIZATION EXTERNAL 7 (TYPE ORACLE_DATAPUMP 8 DEFAULT DIRECTORY ext_dir 9 LOCATION('emp3.dmp') 10 )REJECT LIMIT UNLIMITED; SQL> DESC emp3_ext Name Null? Type ----------------------------------------------------- ----------- ---------------------------------------- EMPID NUMBER(3) ENAME VARCHAR2(20) HIRE_DATE DATE SALARY NUMBER(7) SQL> SELECT * FROM emp3_ext; EMPID ENAME HIRE_DATE SALARY ------------- ---------------- ---------------- ------------ 100 Frank 15-MAY-99 15000 101 Linda 16-SEP-04 20000 102 Gigi 23-FEB-05 7800 103 Wilson 06-SEP-07 10000 當外部表格建立以後,資料庫管理者可以透過 DBA_EXTERNAL_TABLES 查詢外部表格的屬性設定, 也可利用 DBA_EXTERNAL_LOCATIONS 的內容得知資料來源檔案的名字。如果想要知道表格一般資訊 則如同其他表格型態一樣,查詢 DBA_TABLES 即可。 由於外部表格的唯讀特性,因此 ALTER TABLE 的操作僅允許以下幾種: 變更 Reject limit:ALTER TABLE emp_ext REJECT LIMIT 10; 變更 Project 限制:ALTER TABLE emp_ext PROJECT COLUMN REFERENCED; 變更 Access Parameters:ALTER TABLE emp_ext ACCESS PARAMETERS(FIELDS TERMINATED BY WHITESPACE);
  • 32. Chapter 8 Table Oracle Database 11g 資料庫管理入門 變更 Location:ALTER TABLE emp_ext LOCATION(`emp.dat’); 8.4 限制條件(Constraint) 資料完整性(Data Integrity)是指表格中的資料遵守商業規則(Business Rule),意即表格中的資料經過一 些過濾,確定符合事先設定的規範。例如人事規章中規定,每位公司員工必須有一個不能重複的員工編號 以供辨識,同時員工必須歸屬某個已經存在的部門等。為達到此目標,可以使用下列的方法: 前端應用程式檢查:在將資料輸入資料表之前,先使用前端應用程式對資料進行檢查,確定符合資料符合 特定規則,才能存入資料表中。 後端資料庫觸發器檢查:在後端資料庫撰寫觸發器,當資料新增、異動、刪除時便會觸發資料檢查程序, 唯有符合規則的資料才能成功地新增、異動與刪除。 然而前兩種方法都是透過撰寫程式碼達到所需的功能,然而對資料庫管理人員來說,撰寫相關的程式可能 過於困難或麻煩。所以可以先使用資料庫內建的限制條件(Constraint)進行基本、簡單的檢查,當限制條 件做不到所要的功能時,才使用前端應用程式或後端資料庫的觸發器進行更複雜的處理與檢查。 使用限制條件有以下好處: 僅需要宣告即可,不須撰寫複雜的程式碼。 效率較程式碼來的好,因為由 Oracle 核心完成。 限制條件設定在資料庫端,所以任何前端應用程式都會受到規範,不會有遺漏。 8.4.1 限制條件的種類 Oracle 資料庫提供五種限制條件,讓使用者可以依需求選擇合適的限制。以下針對這五種限制條件進行 說明: NOT NULL(不可為空值):NOT NULL 會限制欄位值不可以為空值。不過此種限制條件僅能針對單一欄 位。 UNIQUE KEY(唯一索引鍵):UNIQUE KEY 限制條件的欄位值必須是唯一,也就是欄位值不可與其他資 料列的欄位值重複,此種限制條件可以針對單一欄位或多個欄位所組成的複合值。 PRIMRAY KEY(主索引鍵):其實 PRIMARY KEY 是由 NOT NULL 與 UNIQUE KEY 所共同組成的,因 此欄位值不能為空值,也不能重覆。同時 PRIMARY KEY 限制可以針對一個欄位值或由多個欄位所組成 的複合值,不過一個表格僅能有一個 PRIMARY KEY 限制。若有其他欄位也需要如 PRIMARY KEY 限制 一般的功能,只能使用 NOT NULL 與 UNIQUE KEY 兩個限制結合來達到該要求。 FOREIGN KEY(外來索引鍵):FOREIGN KEY 這種限制條件是要求欄位值必須參考其他欄位中已有的內 容,不能隨心所欲地新增或異動欄位值,不過被參考的欄位必須已經有 PRIMARY KEY 或 UNIQUE KEY 限制條件存在。同時一般稱 FOREIGN KEY 所在的表格為子表格(CHILD TABLE),而被參考的表格為父 表格(PARENT TABLE)。 CHECK(檢查):此種限制是要求欄位值必須讓某個條件式為真(TRUE)後,才允許欄位新增或異動,此種 限制只能針對單一欄位。條件式的範例如下:CHECK(Salary>10000),此限制要求 Salary 欄位值必須 大於 10000。 宣告限制條件可以分成欄位層次(INLINE CONSTRAINT)與表格層次(OUT OF LINE CONSTRAINT)。 NOT NULL 只能使用欄位層次,但若為複合欄限制,則必須採用表格層次。同時採用欄位層次宣告限制 時,不需要在限制條件後加上欄位名稱,但表格層次則必須加上欄位名稱。此外限制條件的名字,可以藉 由 CONSTRAINT 參數設定,若沒有指定,則由 Oracle 伺服器自動產生-(SYS_Cnnnnn,nnnnn 為序列 號)。 SQL> CREATE TABLE frank.con_t1 2 (a NUMBER PRIMARY KEY, --欄位宣告後,立刻接著限制條件的宣告,此為欄位層次 3 b VARCHAR2(10), 4 c DATE,
  • 33. Chapter 8 Table Oracle Database 11g 資料庫管理入門 5 CONSTRAINT con_t1_b_uk UNIQUE(b)); --待所有欄位都宣告後,才宣告限制條件,此為表格層次 SQL> CREATE TABLE frank.con_t2 2 (a NUMBER CONSTRAINT con_t2_a_pk PRIMARY KEY,--使用Constraint參數設定限制條件的名字 3 b VARCHAR2(10), 4 c NUMBER NOT NULL, -- NOT NULL只能使用Column Level 5 CONSTRAINT con_t2_bc_uk UNIQUE(b,c)); --由多個欄位組成的限制條件,必須使用表格層次且必須加上欄位名稱。 SQL> CREATE TABLE frank.con_t3 2 (a NUMBER REFERENCES frank.con_t2(a)); --FOREIGN KEY在欄位層次與表格層次的宣告有些與不同 SQL> CREATE TABLE frank.con_t4 2 (a NUMBER, 3 b NUMBER, 4 CONSTRAINT con_t4_a_fk FOREIGN KEY(a) REFERENCES frank.con_t2(a), 5 CHECK(b>10)); --沒有指定限制條件名稱,將由Oracle伺服器自動指派。 /*可以透過DBA_CONSTRAINTS/ALL_CONSTRAINTS/USER_CONSTRIANTS查知限制條件的相關資訊*/ SQL> SELECT owner,table_name,constraint_name,constraint_type 2 FROM dba_constraints 3 WHERE table_name LIKE 'CON_T%' 4 ORDER BY table_name; OWNER TABLE_NAME CONSTRAINT_NAME C ------------ ---------------------- ------------------------------ --- FRANK CON_T1 CON_T1_B_UK U --U表示為UNIQUE KEY FRANK CON_T1 SYS_C0014764 P --P表示為PRIMARY KEY FRANK CON_T2 CON_T2_BC_UK U FRANK CON_T2 SYS_C0014766 C --C可能是CHECK或NOT NULL FRANK CON_T2 CON_T2_A_PK P FRANK CON_T3 SYS_C0014769 R --R是FOREIGN KEY FRANK CON_T4 SYS_C0014770 C FRANK CON_T4 CON_T4_A_FK R SQL> SELECT constraint_name,constraint_type,search_condition 2 FROM dba_constraints 3 WHERE table_name LIKE 'CON_T%' AND constraint_type='C'; CONSTRAINT_NAME C SEARCH_CONDITION ------------------------------ --- ------------------------------ SYS_C0014766 C "C" IS NOT NULL --依search_condition來區分CHECK與NOT NULL SYS_C0014770 C b>10 --這個限制條件為CHECK
  • 34. Chapter 8 Table Oracle Database 11g 資料庫管理入門 ON DELETE 參數 在宣告 FOREIGN KEY 時,必須指定當父表格資料被刪除,子表格資料要如何處理。共分成以下三種方 式: NO DELETE ACTION:當宣告外鍵時,沒有設定 ON DELETE 參數。表示若父表格的資料列被刪除或 PRIMARY KEY/UNIQUE 限制所在的欄位值被異動時,如果子表格中有任何 FOREIGN KEY 限制的欄位 值受到影響導致違反 FOREIGN KEY 限制條件,則對父表格的刪除或異動將出現錯誤以及自動倒回該操 作。只有被刪除或異動的欄位值沒有被任何 FOREIGN KEY 參考時,才能順利地被刪除或異動。 SQL> CONNCT / AS SYSDBA SQL> CREATE TABLE frank.p_table --父表格 2 (a NUMBER CONSTRAINT p_tab_a_pk PRIMARY KEY, 3 b VARCHAR2(10)); SQL> CREATE TABLE frank.c_table --子表格 2 (a VARCHAR2(10),
  • 35. Chapter 8 Table Oracle Database 11g 資料庫管理入門 3 b NUMBER CONSTRAINT c_tab_b_fk REFERENCES frank.p_table(a)); --沒有ON DELETE設定 --建立父表格的測試資料 SQL> INSERT INTO frank.p_table VALUES(1,'A'); SQL> INSERT INTO frank.p_table VALUES(2,'B'); SQL> INSERT INTO frank.p_table VALUES(3,'C'); SQL> COMMIT; SQL> SELECT * FROM frank.p_table; A B ---------- ---------- 1 A 2 B 3 C --建立子表格測試資料 SQL> INSERT INTO frank.c_table VALUES('A',1); --新增成功,因為P_TABLE的A欄位中有1這個值 SQL> INSERT INTO frank.c_table VALUES('B',10); INSERT INTO frank.c_table VALUES('B',10) * ERROR at line 1: ORA-02291: integrity constraint (FRANK.C_TAB_B_FK) violated - parent key not found --新增失敗,因為P_TABLE的A欄位中並沒有10這個值 SQL> INSERT INTO frank.c_table VALUES('B',3); SQL> COMMIT; SQL> SELECT * FROM frank.c_table; A B ---------- ----------- A 1 B 3 SQL> SELECT table_name,constraint_name,constraint_type,delete_rule,r_constraint_name 2 FROM dba_constraints 3 WHERE table_name IN ('P_TABLE','C_TABLE'); TABLE_NAME CONSTRAINT_NAME C DELETE_RU R_CONSTRAINT_NAME ------------------------------ ------------------------------ -- ---------------- ------------------------------ C_TABLE C_TAB_B_FK R NO ACTION P_TAB_A_PK P_TABLE P_TAB_A_PK P /* 當CONSTRAINT_TYPE為R時,R_OWNER/R_CONSTRAINT_NAME為這個外鍵所參考的限制名稱與限 制擁有者。由以上結果可以得知,C_TABLE的C_TAB_B_FK參考P_TABLE上的P_TAB_A_PK主鍵限制。同 時當父表格被刪除資料或異動主鍵值時,子表格不進行任何動作(DELETE_RULE為NO ACTION)*/ SQL> DELETE frank.p_table WHERE a=2; 1 row deleted. --因為沒有任何子表格的外鍵參考這個欄位值,所以父表格的刪除動作成功完成。 SQL> SELECT * FROM frank.p_table; A B ---------- ---------- 1 A 3 C SQL> DELETE frank.p_table WHERE a=1; DELETE frank.p_table WHERE a=1 *
  • 36. Chapter 8 Table Oracle Database 11g 資料庫管理入門 ERROR at line 1: ORA-02292: integrity constraint (FRANK.C_TAB_B_FK) violated - child record found /*因為有至少一個子表格參考這筆資料列中的A欄位值*/ SQL> UPDATE frank.p_table SET a=2 WHERE a=3; UPDATE frank.p_table SET a=2 WHERE a=3 * ERROR at line 1: ORA-02292: integrity constraint (FRANK.C_TAB_B_FK) violated - child record found /*因為子表格中尚有欄位值參考這筆資料列中的A欄位值*/ SQL> DROP TABLE frank.p_table; DROP TABLE frank.p_table * ERROR at line 1: ORA-02449: unique/primary keys in table referenced by foreign keys /*即便是刪除父表格時,也會受到外鍵的影響。必須先刪除子表格或使用CASCADE CONSTRAINTS的選 項,方可以順利刪除父表格*/ SQL> DROP TABLE frank.p_table CASCADE CONSTRAINTS; Table dropped. /*CASCADE CONSTRAINTS選項會將所有參考此父表格的所有外鍵限制刪除,但不會將子表格一起刪除*/ ON DELETE CASCASE:當設定此種選項後,父表格的資料列被刪除,相對的子表格資料列同時也會被 刪除。但若只有異動 PRIMRARY KEY 或 UNIQUE KEY 的欄位值,還是會檢查是否有子表格的欄位參考 這些欄位值,如果有被參考,依然會出現違反 Reference Integrity 的錯誤訊息。 SQL> CREATE TABLE frank.p_table --父表格 2 (a NUMBER CONSTRAINT p_tab_a_pk PRIMARY KEY, 3 b VARCHAR2(10)); SQL> CREATE TABLE frank.c_table --子表格 2 (a VARCHAR2(10), 3 b NUMBER CONSTRAINT c_tab_b_fk REFERENCES frank.p_table(a) 4 ON DELETE CASACDE); --建立父表格的測試資料 SQL> INSERT INTO frank.p_table VALUES(1,'A'); SQL> INSERT INTO frank.p_table VALUES(2,'B'); SQL> INSERT INTO frank.p_table VALUES(3,'C'); SQL> COMMIT; SQL> SELECT * FROM frank.p_table; A B ---------- ---------- 1 A 2 B 3 C --建立子表格測試資料 SQL> INSERT INTO frank.c_table VALUES('A',1); SQL> INSERT INTO frank.c_table VALUES('B',3); SQL> COMMIT; SQL> SELECT * FROM frank.c_table; A B ---------- -----------
  • 37. Chapter 8 Table Oracle Database 11g 資料庫管理入門 A 1 B 3 SQL> SELECT table_name,constraint_name,constraint_type,delete_rule,r_constraint_name 2 FROM dba_constraints 3 WHERE table_name IN ('P_TABLE','C_TABLE'); TABLE_NAME CONSTRAINT_NAME C DELETE_RU R_CONSTRAINT_NAME ------------------------------ ------------------------------ -- ---------------- ------------------------------ C_TABLE C_TAB_B_FK R CASCADE P_TAB_A_PK P_TABLE P_TAB_A_PK P --當DELETE_RULE為CASCADE,表示FOREIGN KEY的選項為ON DELETE CASCADE SQL> DELETE frank.p_table WHERE a=1; 1 row deleted. SQL> SELECT * FROM frank.p_table; --父表格 A B ---------- ---------- 2 B 3 C SQL> SELECT * FROM frank.c_table; --子表格中所有B欄位為1的資料列 A B ---------- ----------- B 3 SQL> UPDATE frank.p_table SET a=10 WHERE b='C'; UPDATE frank.p_table SET a=10 WHERE b='C' * ERROR at line 1: ORA-02292: integrity constraint (FRANK.C_TAB_FK) violated - child record found /*因為子表格中尚有欄位值參考這筆資料列中的A欄位值*/ ON DELETE SET NULL: 當設定此種選項後,父表格的資料列被刪除,相對的子表格資料列雖不會被 刪除,但 FOREIGN KEY 限制條件的欄位值將會被更改為 NULL(空值)。但若只有異動 PRIMRARY KEY 或 UNIQUE KEY 的欄位值,還是會檢查是否有子表格的欄位參考這些欄位值,如果有被參考,依然會出 現違反 Reference Integrity 的錯誤訊息。 SQL> CREATE TABLE frank.p_table --父表格 2 (a NUMBER CONSTRAINT p_tab_a_pk PRIMARY KEY, 3 b VARCHAR2(10)); SQL> CREATE TABLE frank.c_table --子表格 2 (a VARCHAR2(10), 3 b NUMBER CONSTRAINT c_tab_b_fk REFERENCES frank.p_table(a) 4 ON DELETE SET NULL); --建立父表格的測試資料 SQL> INSERT INTO frank.p_table VALUES(1,'A'); SQL> INSERT INTO frank.p_table VALUES(2,'B'); SQL> INSERT INTO frank.p_table VALUES(3,'C');
  • 38. Chapter 8 Table Oracle Database 11g 資料庫管理入門 SQL> COMMIT; SQL> SELECT * FROM frank.p_table; A B ---------- ---------- 1 A 2 B 3 C --建立子表格測試資料 SQL> INSERT INTO frank.c_table VALUES('A',1); SQL> INSERT INTO frank.c_table VALUES('B',3); SQL> COMMIT; SQL> SELECT * FROM frank.c_table; A B ---------- ----------- A 1 B 3 SQL> SELECT table_name,constraint_name,constraint_type,delete_rule,r_constraint_name 2 FROM dba_constraints 3 WHERE table_name IN ('P_TABLE','C_TABLE'); TABLE_NAME CONSTRAINT_NAME C DELETE_RU R_CONSTRAINT_NAME ------------------------------ ------------------------------ -- ---------------- ------------------------------ C_TABLE C_TAB_B_FK R SET NULL P_TAB_A_PK P_TABLE P_TAB_A_PK P --當DELETE_RULE為SET NULL,表示FOREIGN KEY的選項為ON DELETE SET NULL SQL> DELETE frank.p_table WHERE a=1; 1 row deleted. SQL> SELECT * FROM frank.p_table; A B ---------- ---------- 2 B 3 C SQL> SELECT * FROM frank.c_table; --子表格中受影響的外鍵欄位值被改為NULL,但未被刪除 A B ---------- ----------- A B 3 SQL> UPDATE frank.p_table SET a=10 WHERE b='C'; UPDATE frank.p_table SET a=10 WHERE b='C' * ERROR at line 1: ORA-02292: integrity constraint (FRANK.C_TAB_FK) violated - child record found 外鍵欄位上的索引 由之前的範例與說明得知,有設定 ON DELETE CASCASE 或 ON DELETE SET NULL 時,父表格的 刪除會導致子表格的資料列被刪除或欄位值改為 NULL(空值),這時不光是父表格需要一些鎖定(Table
  • 39. Chapter 8 Table Oracle Database 11g 資料庫管理入門 Level 的 Row Exclusive 及 Row Level 的 Exclusive) ,同時子表格上也需要一些鎖定(Lock)。至於需要 何種型態的子表格鎖定,根據 Foreign Key 限制條件所在的欄位上是否有索引存在而有所不同。如果 Foreign Key 的欄位上沒有索引存在,則在任何 ON DELETE 設定下,都會先取得子表格(Table Level 的 Share Row Exclusive)。然而在握有子表格 Share Row Exclusive 的期間,將會禁止其他 Session 對 子表格進行任何 DML 與 DLL 操作,直到釋放 Share Row Exclusive 為止。不過自 Oracle9i 後,當完成 對子表格刪除或異動後,立刻就降為 Row Exclusive(不會禁止其他 Session 對子表格的 DML,僅禁止 DDL 操作),所以整體的鎖定競爭已經比 Oracle9i 之前的版本少,但是若同時有多個 Session 對父表格 進行 DML 操作,這時子表格還有可能會有嚴重的鎖定競爭發生。 然而若在子表格的 Foreign Key 欄位上建立一個索引,對子表格的鎖定則直接就是 Row Exclusive(僅禁 止 DDL),不需要先取得 Share Row Exclusive,如此 ON DELETE 參數所造成的子表格鎖定競爭將大 幅減少。 --以SYSDBA身份登入 SQL> CONNECT / AS SYSDBA SQL> SELECT sid,type,id1,id2,lmode,request FROM v$lock WHERE TYPE IN ('TX','TM'); no rows selected --目前整個資料庫中,暫時還沒有Table Level與Row Level的Lock發生 SQL> lock table frank.c_table in exclusive mode; /*人工取得對子表格的Table Level Lock,exclusive mode為獨佔模式,不允許其他Session同時握有任何型 態的Table Level Lock在子表格上。這個動作只是為了解Parent Table與Child Table間的鎖定關係而做,正 式環境中盡量不要使用人工要求鎖定的操作,以免影響正常的鎖定行為。*/ SQL> SELECT sid,type,id1,id2,lmode,request FROM v$lock WHERE TYPE IN ('TX','TM'); SID TY ID1 ID2 LMODE REQUEST ----------- ---- -------------- ----------- ------------ -------------- 253 TM 84747 0 6 0 SQL> SELECT owner,object_name,object_type FROM dba_objects WHERE object_id=84747; OWNER OBJECT_NAME OBJECT_TYPE ------------------------------ ----------------------------------- ---------------------- FRANK C_TABLE TABLE /*當LOCK TYPE為TM時,ID1為該物件的Object_ID*/ --開啟另一個Session SQL> SELECT * FROM frank.p_table; --p_table為Parent Table A B ---------- ---------- 2 B 3 C 1 A SQL> SELECT * FROM frank.c_table; --c_table為Child Table,Foreign Key為ON DEELET SET NULL A B ---------- ---------- A 1 B 3 SQL> DELETE frank.p_table WHERE a=1; /*因為frank.c_table已經被其他人握有Table Level:Exclusive Lock,所以現在正在等待frank.c_table上的L ock*/ 回到SYS的Session SQL> select sid,type,id1,id2,lmode,request from v$lock where type in ('TX','TM');
  • 40. Chapter 8 Table Oracle Database 11g 資料庫管理入門 SID TY ID1 ID2 LMODE REQUEST ----------- ---- -------------- ---------- ----------- -------------- 238 TM 84745 0 3 0 --DML所取得的Row Exclusive 238 TM 84747 0 0 5 --想要取得的TM:Share Row Exclusive 253 TM 84747 0 6 0 --人工取得的TM:Exclusive /*因為Child Table上已經有人取得Exclusive Lock,所以ON DELETE想要的Share Row Exclusive必須等 待,此外對Parent Table的DML操作已取得Row Exclusive。*/ SQL> SELECT owner,object_name,object_type FROM dba_objects WHERE object_id=84745; OWNER OBJECT_NAME OBJECT_TYPE ------------------------------ ----------------------------------- ---------------------- FRANK P_TABLE TABLE SQL> COMMIT; --釋放Child Table上的Exclusive Lock SQL> SELECT sid,type,id1,id2,lmode,request FROM v$lock WHERE TYPE IN ('TX','TM'); SID TY ID1 ID2 LMODE REQUEST ----------- ---- -------------- ---------- ----------- -------------- 238 TM 84745 0 3 0 238 TM 84747 0 3 0 --當取得SRX開始進行DML,之後立刻降級為RX 238 TX 524316 12486 6 0 --取得Table Lock後,接著取得Row Lock 8.4.2 限制條件的操作 新增或刪除限制條件 所有的限制條件都可以隨時新增或刪除,除了 NOT NULL 必須使用 ALTER TABLE MODIFY 的語法外, 其餘的限制條件可以使用表格層次的方法新增限制或 ALTER TABLE MODIFY 的語法新增限制。 SQL> CREATE TABLE frank.t1 2 (a NUMBER, 3 b VARCHAR2(10)); SQL> DESC frank.t1 Name Null? Type ----------------------------------------------------- -------------- ---------------------------------------- A NUMBER B VARCHAR2(10) SQL> ALTER TABLE frank.t1 2 MODIFY (a NUMBER CONSTRAINT t1_a_nn NOT NULL); --NOT NULL必須使用MODIFY SQL> DESC frank.t1 Name Null? Type ----------------------------------------------------- -------------- ---------------------------------------- A NOT NULL NUMBER B VARCHAR2(10) SQL> ALTER TABLE frank.t1 2 ADD CONSTRAINT t1_a_pk PRIMARY KEY(a); --新增一個PRIMARY KEY限制條件 SQL> ALTER TABLE frank.t1 2 DROP CONSTRAINT t1_a_pk CASCADE; /*刪除一個限制時,若該限制為PRIMARY KEY或UNIQUE KEY要加上CASCADE ,同時將子表格的FOREI GN KEY限制條件刪除*/
  • 41. Chapter 8 Table Oracle Database 11g 資料庫管理入門 8.4.3 限制條件的狀態 限制條件的狀態影響限制對新增資料的檢查與否以及對現存資料的驗證,其中根據 DISABLE/ENABLE 與 NOVALIDATE/VALIDATE 組成四種情況: DISBALE NOVALIDATE:當限制條件的狀態為 DISABLE NOVALIDATE 時,表示雖然表格上有設定 限制條件,但是並不會對新增的資料列進行檢查,同時也不會驗證表格中已經存在資料列是否遵守限制。 也就是說限制條件只是一個宣告,但完全不會發生任何功能。 ENABLE NOVALIDATE:當限制條件的狀態為 ENABLE NOVALIDATE 時,表示新增的資料列必須遵 守限制條件的規範,才能新增到表格中,不過已經存在表格中的資料列並不一定要遵守限制條件的規範。 所以現在的表格中的資料,可能還有一些資料是違反限制條件的規範,但至少從現在開始新增的資料一定 會遵守限制條件的規範。 ENABLE VALIDATE:當限制條件的狀態為 ENABLE VALIDATE 時,表示新增的資料列必須遵守限制 條件的規範,才能新增到表格中,同時也驗證已經存在表格中的資料也都遵守限制條件的規範。這種狀態 是宣告限制條件的預設狀態。 DISABLE VALIDATE:當限制條件的狀態為 DISABLE VALIDATE 時,表示新增的資料列不須遵守限 制條件的規範,也可以新增到表格中,不過所以已經存在的資料一定遵守限制條件的規範。這樣的狀態有 一點自相矛盾,因為如果一筆違反限制條件的資料列成功新增到表格中,那麼要如何達到已經存在的資料 列一定遵守限制條件呢?最簡單的方法是禁止這個表格的 DML 操作,就不會有這種問題發生。所以當狀 態為 DISABLE VALIDATE 時,限制所在的表格是不允許被新增、異動或刪除。這種狀態是用在當表格 與分區表格(Partition Table)的區段(Segment)進行交換操作時,所有的限制條件都必須是此種狀態,才 能順利進行區段的交換。 SQL> DROP TABLE frank.t1; --刪除frank.t1表格 SQL> CREATE TABLE frank.t1 2 (a NUMBER CONSTRAINT t1_a_ck CHECK(a>=10), 3 b VARCHAR2(10)); SQL> SELECT status,validated FROM dba_constraints 2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK'; STATUS VALIDATED ------------------ ----------------- ENABLED VALIDATED --宣告限制條件的預設狀態 SQL> ALTER TABLE frank.t1 DISABLE NOVALIDATE CONSTRAINT t1_a_ck; /*如果只有DISABLE表示為DISABLE NOVALIDATE。若限制條件為PRIMARY KEY或UNIQUE,需要加上C ASCADE將子表格上FOREIGN KEY的狀態也改為DISABLE*/ SQL> SELECT status,validated FROM dba_constraints 2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK'; STATUS VALIDATED ------------------ ------------------------ DISABLED NOT VALIDATED SQL> INSERT INTO frank.t1 VALUES(10,'A'); SQL> INSERT INTO frank.t1 VALUES(1,'B'); --1小於10,但依然可以成功新增,因為狀態為DISABLED SQL> COMMIT; SQL> SELECT * FROM frank.t1; A B ------------ ---------- 10 A
  • 42. Chapter 8 Table Oracle Database 11g 資料庫管理入門 1 B SQL> ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINT t1_a_ck; ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINT t1_a_ck * ERROR at line 1: ORA-02293: cannot validate (FRANK.T1_A_CK) - check constraint violated /*已經存在的資料列中,有些違反限制條件的規範,所以不能將狀態設為VALIDATE。必須自行將違反限制條 件的資料進行清理後,才能將狀態設為VALIDATE*/ SQL> ALTER TABLE frank.t1 ENABLE NOVALIDATE CONSTRAINT t1_a_ck; /*退而求其次地將狀態條件先設定為ENABLE NOVALIDATE,避免有更多違反限制條件的資料列被新增,之 後再將違反限制條件的資料列修正,再將狀態改為ENABLE VALIDATE即可。如果只有ENABLE則表示為EN ABLE VALIDATE*/ SQL> SELECT status,validated FROM dba_constraints 2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK'; STATUS VALIDATED ------------------ ------------------------ ENABLED NOT VALIDATED SQL> INSERT INTO frank.t1 VALUES(2,'C'); --2比10小,所以無法新增 INSERT INTO frank.t1 VALUES(2,'C') * ERROR at line 1: ORA-02290: check constraint (FRANK.T1_A_CK) violated SQL> INSERT INTO frank.t1 VALUES(20,'C'); SQL> COMMIT; SQL> SELECT * FROM frank.t1; A B ------------ ---------- 10 A 1 B 20 C 找出那些資料列違反限制條件的規範,首先必須先建立一個表格 EXCEPTIONS,這個表格利用 $ORACLE_HOME/rdbms/admin/utlexpt1.sql 產生。再利用 ALTER TABLE EXCEPTIONS 語法將違 反某個限制條件的資料列 ROWID 填入 exceptions 表格,如此便可以得知哪些資料列違反限制條件。 SQL> @$ORACLE_HOME/rdbms/admin/utlexpt1.sql SQL> DESC exceptions Name Null? Type ----------------------------------------------------------- ----------------- ---------------------------------------- ROW_ID ROWID OWNER VARCHAR2(30) TABLE_NAME VARCHAR2(30) CONSTRAINT VARCHAR2(30) SQL> SELECT row_id FROM exceptions 2 WHERE owner='FRANK' AND table_name='T1' AND constraint='T1_A_CK';
  • 43. Chapter 8 Table Oracle Database 11g 資料庫管理入門 no rows selected SQL> ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINT t1_a_ck 2 EXCEPTIONS INTO exceptions; --將違反t1_a_ck的資料列ROWID新增到exceptions表格中 ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINT t1_a_ck * ERROR at line 1: ORA-02293: cannot validate (FRANK.T1_A_CK) - check constraint violated SQL> SELECT row_id FROM exceptions 2 WHERE owner='FRANK' AND table_name='T1' AND constraint='T1_A_CK'; ROW_ID -------------------------------------------------------------------------------------------------------------- AAAUsOAAEAAAAP6AAB --這筆ROW違反t1_a_ck SQL> SELECT search_condition FROM dba_constraints 2 WHERE constraint_name='T1_A_CK' AND table_name='T1' AND owner='FRANK'; SEARCH_CONDITION -------------------------------------------------------------------------------- a>=10 SQL> SELECT * FROM frank.t1 2 WHERE rowid IN (SELECT row_id FROM exceptions 3 WHERE owner='FRANK' AND table_name='T1' AND constraint='T1_A_CK'); A B ----------- ---------- 1 B /*修正違反t1_a_ck的資料列,讓它遵守t1_a_ck的規範*/ SQL> UPDATE frank.t1 SET a=11 WHERE rowid='AAAUsOAAEAAAAP6AAB'; 1 row updated. SQL> SELECT * FROM frank.t1 WHERE rowid='AAAUsOAAEAAAAP6AAB'; A B ----------- ---------- 11 B SQL> DELETE exceptions WHERE owner='FRANK' AND table_name='T1' AND constraint='T1_A_CK'; /*清除exceptions表格中已經處理過的資料列*/ SQL> COMMIT; SQL> SELECT * FROM frank.t1; A B ----------- ---------- 10 A 11 B 20 C SQL> ALTER TABLE frank.t1 ENABLE VALIDATE CONSTRAINTS t1_a_ck; SQL> SELECT status,validated FROM dba_constraints
  • 44. Chapter 8 Table Oracle Database 11g 資料庫管理入門 2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK'; STATUS VALIDATED ------------------ ----------------- ENABLED VALIDATED /*未來新增的資料必須遵守限制條件,同時已經存在的資料列也經過驗證確定遵守限制條件的規範*/ SQL> ALTER TABLE frank.t1 DISABLE VALIDATE CONSTRAINT t1_a_ck; SQL> SELECT status,validated FROM dba_constraints 2 WHERE owner='FRANK' AND table_name='T1' AND constraint_name='T1_A_CK'; STATUS VALIDATED ------------------ ----------------- DISABLED VALIDATED --此種狀態下,表格不允許DML操作 SQL> INSERT INTO frank.t1 VALUES(40,'D'); INSERT INTO frank.t1 VALUES(40,'D') * ERROR at line 1: ORA-25128: No insert/update/delete on table with constraint (FRANK.T1_A_CK) disabled and validate d 8.4.4 不可延緩與可延緩的限制條件 當表格的限制條件狀態為 ENABLE 時,新增的資料列必須遵守限制條件的規範才能被新增。然而何時進 行這個檢查,分成 DML 指令結束(IMMEDIATE)或交易結束(DEFERRED)兩種。 NOT DEFERRABLE(不可延緩) 然而當建立限制條件時,如果沒有明確指定限制條件可以延緩(DEFERRABLE),則限制條件的狀態就只 能為不可延緩(NOT DEFERRABLE)。而且事後也不可以更改,必須刪除現存的限制條件,重新建立一個 可以延緩的限制條件。如此該限制條件只能在 DML 指令結束後,立刻檢查該 DML 指令的結果是否遵守 限制條件的規範,如果違反限制條件的規範,該 DML 指令的結果將立刻被倒回(ROLLBACK),但是整個 交易(Transaction)依然存在不會倒回。 SQL> CREATE TABLE frank.t2 2 (a NUMBER CONSTRAINT t2_a_pk PRIMARY KEY, --此限制條件預設為NOT DEFERRABLE 3 b VARCHAR2(10)); SQL> SELECT deferrable,deferred 2 FROM dba_constraints 3 WHERE owner='FRANK' AND table_name='T2' AND constraint_name='T2_A_PK'; DEFERRABLE DEFERRED ------------------------------- ---------------- NOT DEFERRABLE IMMEDIATE SQL> INSERT INTO frank.t2 VALUES(1,'A'); SQL> INSERT INTO frank.t2 VALUES(2,'B'); SQL> INSERT INTO frank.t2 VALUES(1,'C'); INSERT INTO frank.t2 VALUES(1,'C') * ERROR at line 1: ORA-00001: unique constraint (FRANK.T2_A_PK) violated /*此INSERT違反PRIMARY KEY,因此該INSERT的結果被倒回(ROLLBACK),但整個交易並未倒回或確認 (COMMIT)*/ SQL> SELECT * FROM frank.t2; --並未倒回整個交易