一.1 數據庫
與Sybase不同,一個用戶就對應於一個數據庫。
create user CBMAIN
identified by "sunline"
default tablespace CBMAIN_DATA -- 表空間
temporary tablespace CBMAIN_TEMP; -- 臨時表空間
一.2 表空間
表空間由一個或多個物理文件組成,一個表空間只能用於一個數據庫。
create temporary tablespace CBMAIN_TEMP datafile
'D:\Oradata\CBMAIN_TEMP01.dbf' size 200M,
'D:\Oradata\CBMAIN_TEMP02.dbf' size 200M
一.3 登錄身份
與Sybase不同,用戶登錄時需指定身份登錄。 分為Normal、sysdba、sysoper
三種不同身份。各自對數據庫擁有的權限不同,sysdba最高,normal 最低。如:
c:\> sqlpuls /nolog
sql>connect sys as sysdba
一.4 普通數據類型
Varchar2\Varchar:在建表語句中系統保留使用varchar,但建立的表結構實際為varchar2。PL\SQL中只允許使用varchar2。
Char:在建表語句中,字段內容長度固定可使用char,如狀態字段。其它情況下不建議使用Char來建表。
Boolean:不能用於建表,只用於PL\SQL;
Date\Timestamp:日期時間型,可用於建表,也可用於PL\SQL語句編寫。但在Ltts5.0表結構設計中不對其做廣泛應用,日期字段用char(8)來存儲。
Sys_refcursor:游標數據類型,采用此種類型定義的游標,在定義時無須編寫SELECT子句,打開時采用Open Cur_var For Select c1,c2 from tab1的方式。
一.5 結構
類似於C中的結構體,常在包、過程、函數中定義。如:
TYPE t_Result IS RECORD(
Instam NUMBER(18, 2) default 0.00,
Intxst NUMBER(18, 2) default 0.00,
Intxam NUMBER(18, 2) default 0.00,
Sqltxt VARCHAR2(2000),
Instrt NUMBER(11, 7)
);
行類型(rowtype)是個特殊的結構體,select * into xxxx時即可into到行類型變量,也可into到要素雷同的結構體。
常用於返回結果(Oracle out 型的參數必須傳入,便於擴展)。
一.6 包
包具有部分OO特征:封裝性、多態性。
簡單的理解為一個容器,可以將若干個過程或者函數組合成一個更大的單位。
包體編寫過程體或函數體,包頭申明過程說明或函數說明。只有在包頭申明過的過程或函數才能被外部程序調用。
除過程和函數外,還可以申明包變量、常量、結構;其中包頭定義可以被外部直接訪問或修改(public)。包體部分定義的只能被包自身訪問(priavte)。
包的生命周期:起始於此包的第一次調用,結束於當前session的斷開。根據此特性,可用包頭或包體的變量、常量、結構存儲運算結果,甚至是系統級別的參數緩存。
不建議在包頭申明變量;通常方法是在包體申明變量同時配以一組方法訪問它。
通常在包頭定義某個結構,用來在過程傳遞或返回一組信息。
- 常用系統包
UTL_FILE ----------處理外部文件
DBMS_OUTPUT ----調試PL/SQL,DEBUG
DBMS_SQL ----------執行動態SQL PL\SQL
dbms_job ------管理JOB
dbms_system -------跟蹤用戶,SESSION
dbms_transaction -------- 管理SQL事務
一.7 過程與函數
原則上,過程和包不允許獨立編寫,必須封裝在包中。
與sybase不同, out 型的參數必須傳入,不能缺省。
函數雖可定義out型變量,但不建議如此應用。當且僅當所實現只返回一個(含預估未來)基礎數據類型(字符、數字、布爾、日期)的時候才將此功能申明為函數。其它情況下都申明為方法。
在包頭有申明的過程在定義out型變量時,建議用一個結構體。目的是在未來擴展輸出參數時,無須修改已修改的代碼。
過程或函數定義基礎類型參數時,varchar2, number 等即可。沒必要使用用戶自定義類型如:sys_type.u_acctno%type 或者kna_accs.acctno%type;
對於out 或in out 參數定義時 nocopy 關鍵字的意義:
不加nocopy傳遞的是復制(by value),否則傳遞的是地址(by reference)。
傳遞地址對大型結構或大數據時可以提高效率。
在出現異常時,不加nocopy的情況下,外層程序讀到的仍然是原值。加nocopy的情況下,若有修改,外層程序讀到的是修改之后的值。因此使用nocopy 時,需要確保在被調用過程中處理所有的異常。
一.8 事務
Sybase需要用Begin tran來控制是否需要手動commit或rollback; Oralce無此語句,但有一開關Set autocommit OFF/ON;將commit或rollback的權力交給用戶。默認關閉,即由用戶來控制事務的提交或回滾;也就沒有事務積數器這一全局變量(@@transcount)。
- DDL語句與事務
Alter … create …等都屬於DDL語句。
由於Oracle執行DDL語句時會自動調用Commit,因此禁止在業務程序里使用DDL語句。
- 獨立事務
PRAGMA AUTONOMOUS_TRANSACTION;
可在某個子過程或函數中單獨申明一段事務,有關其涉及到的業務邏輯處理,由自身commit或rollback,不會影響到主程序已處理的事務。
注意:函數中若有事務語句,必須申明獨立事務。即:若無特殊情況,涉及事務處理都不寫成函數,都應寫成過程。
相關應用:生成流水號、記錄密碼錯誤等。
一.9 異常
- 概念要點
Sybase由系統控制異常,Oracle則可主動捕捉異常。每當PL/SQL違背了ORACLE原則或超越了系統依賴的原則就會隱式的產生內部異常。
異常分為兩類:分為系統異常和用戶自定義異常。用戶定義異常則需要顯現的拋出。
拋出方式 |
異常類型 |
通過PL/SQL運行引擎 |
系統內部異常 |
使用RAISE語句 |
用戶定義異常 |
調用RAISE_APPLICATION_ERROR存儲過程 |
用戶定義異常 |
異常處理是用來處理正常執行過程中未預料的事件。如果PL/SQL程序塊一旦產生異常而又沒有指出如何處理時,程序會自動終止。
系統內部異常分為:預定義的內部異常和未定義內部異常。未定義內部異常只能在Other部分捕捉。
常見預定義異常 |
sqlerrm |
sqlcode |
描述 |
no_data_found |
ora-01403 |
+100 |
Select into無符合條件的記錄 |
too_many_rows |
ora-01422 |
-1422 |
Select into符合條件的記錄有多條 |
dup_val_on_index |
ora-00001 |
-1 |
違反唯一約束 |
value_error |
ora-06502 |
-6502 |
發生算數、轉換、截斷或大小約束錯誤 |
storage_error |
ora-06500 |
-6500 |
內存溢出 |
zero_divide |
ora-01476 |
-1476 |
除數為零 |
case_not_found |
ora-06592 |
-6530 |
無匹配when子句也無默認else子句 |
cursor_already_open |
ora-06511 |
-6511 |
試圖打開已經打開的游標 |
timeout_on_resource |
ora-00051 |
-51 |
等待某一資源,超時 |
access_into_null |
ora-06530 |
-6530 |
試圖給未初始化對象的屬性賦值 |
invalid_cursor |
ora-01001 |
-1001 |
游標操作錯誤,如:關閉未打開 |
login_denied |
ora-01017 |
-1017 |
登錄時用戶名或密碼非法 |
program_error |
ora-06501 |
-6501 |
PL/SQL內部錯誤 |
rowtype_mismatch |
ora-06504 |
-6504 |
賦值變量與游標返回變量不兼容 |
self_is_null |
ora-30625 |
-30625 |
|
sys_invalid_rowid |
ora-01410 |
-1410 |
字符串轉化成rowid失敗 |
subscript_beyond_count |
ora-06533 |
-6533 |
|
subscript_outside_limit |
ora-06532 |
-6532 |
|
collection_is_null |
ora-06531 |
-6531 |
|
invalid_number |
ora-01722 |
-1722 |
字符串轉化成數字失敗 |
not_logged_on |
ora-01012 |
-1012 |
未連接數據庫前訪問數據 |
- 異常傳播機制:
當異常發生時,若本語句塊未做異常處理,控制將轉到或傳播到外層語句塊的異常處理部分。直到外層捕捉到異常,則運行捕捉異常后語句塊;若外層塊沒有該異常的處理程序則傳播到調用環境,並立即終止。
- SQL與異常規范:
總原則:
任何異常處理必須有Others分支
1.SELECT INTO 語句:
常見no_data_found和too_many_rows異常,也就是說要保證查詢結果有且只有一條數據才不會觸發入上異常。因此不能用 SQL%Rowcount來判斷行數。
若where 條件中包括物理上的唯一索引,則可以不對too_many_rows進行處理。
另:無group by 子句的,SELECT Count(*)、sum、max等聚合函數 INTO 能保證有且僅有一條數據,因此可以不對too_many_rows和 no_data_found進行處理。
2.INSERT 語句:
若插入的表存在唯一索引或主鍵,則需要判斷 dup_val_on_index 異常;
空值異常在 Others 里處理 (ORA-01400);
能用 SQL%Rowcount 來判斷行數。
3.Update語句:
若被修改的列是唯一索引所在列,則需要判斷 dup_val_on_index 異常;
空值異常在 Others 里處理 (ORA-01400);
能用 SQL%Rowcount 來判斷行數。
4.DELETE 語句:
處理Other異常即可,無須其它異常處理
能用 SQL%Rowcount 來判斷行數。
- 異常嵌套:
為了程序結構清晰,應避免異常處理語句中出現異常嵌套;也就是說,異常處理中不應該再編寫可能再次出現異常的語句如如:select、insert、delete、update等語句。可寫成子程序或跳出此語句塊后再處理。
一.10 臨時表
不同於Sybase,臨時表必須事先創建好。
臨時表獨立於每個session,也就是說,A連接不可能訪問到B連接臨時表中的數據。臨時表有兩種創建形式:
commit preserve rows,隨着事務提交保存。數據一直存儲,直到當前session斷開。因此,在此種情況下,去維護臨時表的表結構是行不通的。
commit delete rows,隨着事務提交時清空。若只是用於中間計算,可用此種形式。
小技巧:臨時表所有字段均為空,以便適用於不同場景。
一.11 哈希表
也稱關聯數組、索引表。是普通集合的擴展,可以用健值獲得數組中的值。
優點,鍵值唯一,訪問速度快。
- 普通集合
Type t_array is table of varchar2(20)
L_array t_array := {‘John’, ‘Susan’};
Dbms_Output.Put_Line(l_Array(2)); -- 下標
- 哈希表
Type t_array_hash is table of varchar2(20) index by varchar2(4);
L_array_hash t_array_hash;
L_array_hash(‘0001’) := ‘John’;
L_array_hash(‘0002’) := ‘Susan’;
Dbms_Output.Put_Line(l_Array_Hash('0001')); -- 鍵值
- 單主鍵表轉為一維哈希表
如有下表(userid varchar2(5) is primary key, userna varchar2(20), brchno varchar2(6) )
TYPE t_User_Rec IS RECORD( -- 先對主鍵外字段建立“記錄型”用戶自定義類型
userna VARCHAR2(20),
brchno VARCHAR2(6)
);
-- 在結構上建立哈希表
TYPE t_User_tab IS TABLE OF t_User_Rec INDEX BY VARCHAR2(5);
l_User_Rec t_User_Rec; --申明記錄變量
l_User_tab t_User_tab; --申明表變量
l_Userna varchar2(20); --普通變量
-- 哈希表插入記錄
l_User_Rec.userna = ‘李大照’; l_User_Rec.brchno = ‘010201’;
l_User_tab(‘用戶1’) := l_User_Rec; -- 記錄1
l_User_Rec.userna = ‘王虎’; l_User_Rec.brchno = ‘019801’;
l_User_tab(‘00002’) := l_User_Rec; -- 記錄2
-- 訪問記錄
l_Userna = l_User_tab(‘00002’).Userna;
- 雙主鍵表轉為二維哈希表
如上表需增加維度行號(bankno varchar2(12) is primary key, userid varchar2(5) is primary key,…)
…
-- 需要增加的工作是對一維哈希表再建立一層哈希表
TYPE t_Bank_User_tab IS TABLE OF t_User_tab INDEX BY VARCHAR2(12);
l_User_Rec t_User_Rec; --申明記錄變量
l_bank_user t_Bank_User_tab --申明二維表變量
l_Userna varchar2(20); --普通變量
-- 哈希表插入記錄
l_User_Rec.userna = ‘李大照’; l_User_Rec.brchno = ‘010201’;
l_User_tab(‘武漢分行’)(‘用戶1’) := l_User_Rec; -- 記錄1
l_User_Rec.userna = ‘王虎’; l_User_Rec.brchno = ‘019801’;
l_User_tab(‘常洲分行’)(‘00002’) := l_User_Rec; -- 記錄2
-- 訪問記錄
l_Userna = l_User_tab(‘常洲分行’)(‘00002’).Userna;