前言:
本文純為牢騷, 怨言, 一為筆者對ORACLE軟件如此這般的疑惑與不滿,
二來其實可以總結ORACLE中的一些不規則性, 為ORACLE學習者提供一些借鑒.
三來看起當時的心情頗為抓狂, 寫下來, 算是對一些不良心態的反思.
有一些是筆者早期初涉ORACLE時的一些誤解, 冤枉它了. 在後記中都有正名.
1. 改變當前用戶時SQLPLUS環境變量的設置是否被繼承到新的用戶環境下
混亂, serverout 沒有被繼承, 而pagesize被繼承.
2. SQLPLUS環境下命令行編輯功能微弱得可憐, 看看readline, 看看MySQL
3. SQLPLUS環境的命令行沒有歷史記錄功能, 看看MySQL. gdb, bash
4. 命名規范混亂得一踏糊塗. user_tab_columns, user_con_constraints
user_tables, usre_cons_columns
5. SQLPLUS環境的初始化文件的location的要求, 看看.bashrc, .vimrc, .netrc
.emacs, .newsrc...摸一個都比它強, 我要使用你的login.sql還非得在每
一個當前目錄下都弄一份, 隨身攜帶呀? 好在這一點可以通過SQLPATH環境
變量的設置來搞定.
6. 注釋格式:--, 什麼玩意呀, HTML用, perl用#, php用#或/**/或
//, C用/**/, C++用/**/和//, lisp用;;, 匯編用;, QBASIC用rem 和',
SHELL,SED,AWK用#, 你干嗎要自創一種. 自以為很鳥啊, 與別人兼容一點會
小你什麼身份.
7. 看看它的PL/SQL, 號稱第N代的高級語言, function因為必需返回一個值而
存在, 除此之外我看不出它與其它的procedure有什麼區別. 又是trigger,
又是package, 又是procedure, 又是function, 搞什麼東東呀. 別人是把
復雜的東西簡單化, 我看ORACLE是要把簡單的東西復雜化, 同樣是PL/SQL
程序, dbms_output.put_line被設計成在function裡單獨調用時不能輸出.
非要一個procedure單獨調用它時它才會輸出.
8. 單引號問題, Javascript可以兼容使用單雙引號, perl可以, php也可以, 它
們可以是因為它們想兼容, 想對用戶友好, C語言不允許, 那是因為它嚴謹.
人家留著有大用場. 你ORACLE不允許使用雙引號又是什麼原由, 說來聽聽.
9. 別人的用戶界面設計是"沒有消息就是最好的消息", 或是"無論發生什麼, 都
要讓用戶知道", 看看它在sqlplus下的變量:
var i number;
i:=5;
print i;
你什麼看見什麼, 什麼都沒有! 你又能從這知道什麼, 好消息?
PS:我至今都不知道這說明了什麼? i的值為NULL?, i不能在這下面賦值?
不能賦值你說呀, 你不說我怎麼知道不能賦值, 雖然你很能有意見地顯示了
一個空行, 但是你還是要說呀, 你真的不能賦值嗎? 你不是真的不能賦值吧?
...
後記: 好在我今天知道了要用
SQL> exec :i := 5;
SQL> print :i
但總不能讓我掘地三尺才找得出來這些淺顯的東西吧.
10. 在sqlplus下help set看看, 找出一個叫set severout[put] on|off的選項
注意, 它是severout, 你在sqlplus下set severout on試試,
SP2-0158: unknown SET option "severout" 了吧?
set serverout on
是的, 就一個字母而已.
編程大師說: 任何軟件都有BUG.
但, 一個如此小的BUG可以讓一個全球第二大的軟件公司帶著它走過幾個版本?
Oracle8.15 Oracle8.16 Oracle8.17...難道保留錯誤是為了兼容性?
後記: 我終於看到Oracle9i版裡對此有了改進, 略感欣慰.
11. PL/SQL的用戶們, 看看下面:
創建一個沒帶參數的procedure:
create or replace procedure proc_name as
i number;
begin
...
end proc_name;
創建一個帶參數的procedure:
create or replace procedure proc_name(arg1,...) as
i number;
begin
...
end proc_name;
你很習慣用declare來聲明嗎? 不行, 這裡不行, 你必需聽我的, 用as
創建一個觸發器:
create or replace trigger tri_name before insert on tname for each
row
declare
i number;
begin
..
end;
因為這是觸發器, 所以它要用declare來聲明變量, 盡管觸發器用的也是PL/
SQL的語法. 但我們是為了區別於其它類型的存儲過程, 為了讓用戶覺得
ORACLE高深莫測一點.
怎麼就一個end;不是end tri_name嗎? 是的, procedure和function是這樣
設計的, 但這樣可以讓用戶覺得更難用一點麼!
(sqlplus下)你調用一個不帶參數的procedure:
call proc_name();
(sqlplus下)你調用一個不帶參數的procedure:
call proc_name(arg1, arg2);
是的, 它不是可選的, 它必需如此, 定義一個沒有參數的procedure就是不
要空的()號, 但調用它的時侯就是要, 定義一個有參數的procedure當然也要.
function的情況與這個也一樣.
你調用一個function:
ret_val := func_name();
什麼? 你不需要ret_val, 不行, 這是強買強賣, 不要不行. 否則我不干活!
而且, 哼哼, 我給出的錯誤信息保證你看不懂.
你要玩更高級的設計方法, 用上包了:
create or replace package pack_name as
....
end pack_name;
是的, 這只是包的聲明.
要想定義這個包, 你還得:
create or replace package body pack_name as
procedure proc_name is
--你不是說用as嗎? 是的, 但是這裡as已經被上一條語句用了, 呶! 你
也看到了. 用is有什麼不好?
end proc_name
function func_name is
...
end func_name
end pack_name;
12. 看看出錯信息, 來自SQLPLUS的, 來自Pro*C預編譯器的, 來自其它工具如
imp, exp, sqllda的. 說不准你也別誤導呀.
13. 疲憊不堪的Pro*C程序員們:
在函數foo中你已經聲明了
EXEC SQL WHENEVER SQLERROR GOTO sql_err;
在另一個函數bar裡你只想默默地使用
EXEC SQL WHENEVER SQLERROR CONTINUE;
但你沒特別聲明, Pro*C的預編譯器會告訴你, 它在函數bar中找不到sql_err
標號!!! 它可以跨函數使用標號. 它也敢自稱是一個預處理器跟編譯器沾沾
邊, 剛才用陳橋五筆敲出來的處理器三個字恰好跟處理品是同樣的鍵碼, 我看
叫處理品倒是名符其實.
14. DDL語句的用戶們:
alter table tname add(col1 type...);
alter table tname modify(col1 type...);
alter table tname drop column(col1);
為何非要在drop裡多出來一個column?
15. 命名
user_cons_columns;
user_constraints;
user_rollback_segs;
它真的要把segment統統縮寫為segs嗎? 把constraints縮寫為cons? 把
columns縮寫為cols? 不, ORACLE的程序員們想怎麼樣就怎麼樣. 他們是覺得
單詞的全稱太長了嗎? 不見得, desc dba_users;看一下
看看INITIAL_RSRC_CONSUMER_GROUP字段, 看看temporary_tablespace字段.
再來看看一下create table:
create table tname (col1 type,...) storage(initial .. next ..
minextents .. maxextents ..) ...;
desc user_tables;
inital_extent
next_extent
minextents
maxextents
不要問他們為什麼有的用單數有的用復數, 因為他們是ORACLE. 他們想這樣.
dba_tables中owner
dba_sequences中叫sequence_owner
user_tab_columns是關於一張表中列信息的, _tab_columns
user_cons_columns是關於表中字段的約束信息的, _cons_columns
後話: 牢騷發完了, 繼續得埋頭搞開發, 寫代碼, 畢竟, 人類在一個fortran語言 大行其道的年代就已經登上了月球, 所以, 爭論語言或工具的優劣強弱還不如把 現有的功能充分高效地利用起來. 如此一說, 算是什麼?