Oracle中的PLsql的符號解釋大全


  一、字符tb

在PL/SQL程序中,允許出現的字符集包括:

大小寫字母(A-Z和a-z)
數字(0-9)
符號( ) + - * / < > = ! ~ ^ ; : . ’ @ % , " # $ & _ | { } ? [ ]
制表符、空格和回車符
PL/SQL對大小寫不敏感,所以,除了在字符串和字符中,小寫字母和它對應的大寫字母是等價的。

  二、詞法單元

PL/SQL包含很多詞法單元(lexical unit),大致可以分為以下幾類:

分隔符(簡單符號和復合符號)
標識符,其中包括關鍵字
文字
注釋
為改善可讀性,我們可以用空格將詞法單元分隔開。實際上,我們必須將相鄰的兩個標識符用空格或標點符號隔開。下面這樣的寫法是不允許的,因為關鍵字END和IF連到一起了:

IF  x > y tdEN  high := x; ENDIF; -- not allowed 

還有,除了字符串和注釋以外,我們不可以在詞法單元中嵌入空格。例如,像下面的賦值符號中間就不用被分開:

count : = count + 1; -- not allowed 

為了讓層次結構清楚,我們可以用回車符來換行,空格或制表符來進行縮進。比較一下下面兩段IF語句的可讀性:

IF  x>y tdEN  max:=x;ELSE  max:=y;END  IF ;  IF  x > y tdEN
  MAX     := x;
ELSE
  MAX     := y;
END  IF ; 

1、分隔符

分隔符是對PL/SQL有着特殊意義的簡單或復合的符號。例如,我們使用加號和減號這樣的分隔符來表現數學運算。簡單分隔符只有一個字符。

符號  含義
+   加法操作符
%  屬性指示符
’    字符串分隔符
.    組件選擇器
/    觸法操作符
(    表達式或列表分隔符
)    表達式或列表分隔符
:    主變量指示符
,    分隔符
*   多應用程序操作符
"    引用標識符分隔符
=   關系操作符
<   關系操作符
>   關系操作符
@  遠程訪問指示符
;  語句終結符
-  減號/負號操作符

復合分割符由兩個字符組成。

符號 含義
:= 賦值操作符
=> 管聯操作符
|| 連接操作符
** 求冪操作符
<< 標簽分隔符(開始)
>> 標簽分隔符(結束)
/* 多行注視分隔符(開始)
*/ 多行注視分隔符(結束)
.. 范圍操作符
<> 關系操作符
!= 關系操作符
~= 關系操作符
^= 關系操作符
<= 關系操作符
>= 關系操作符
-- 單行注釋提示符

2、標識符

我們可以使用標識符來為PL/SQL程序中的常量、變量、異常、游標、游標變量、子程序和包命名。下面是一些標識符的例子:

X
t2
phone#
credit_limit
LastName
oracle$number
標識符可以由字母、數字、美元符號($)、下划線(_)和數字符號(#)組成。而像連字符(-)、斜線(/)等符號都是不允許使用的。如下例:

mine&yours -- 不允許使用連字符(not allowed because of ampersand)
debit-amount -- 不允許使用連字符(not allowed because of hyphen)
on/off -- 不允許使用斜線(not allowed because of slash)
user id -- 不允許使用空格(not allowed because of space)
而使用美元符號、下划線和數字符號都是允許的:

money$$$tree
SN##
try_again_
我們也可以使用大小寫混合的形式來編寫標識符。但是要記住,除了字符串和字符以外,PL/SQL對大小寫是不敏感的。所以,只在大小寫上有區別的標識符,PL/SQL會把它們當做同一標識處理,如下例:

lastname
LastName -- 與lastname相同
LASTNAME -- 與lastname和Lastname相同
標識符的長度不能超過30。對於標識符的命名盡可能代表某種含義,避免使用像cpm這樣的命名,而是使用cost_per_tdousand這樣意義明確的命名方式。

保留關鍵字
對於某些標識符,我們稱它們為保留關鍵字(reserved word),因為對於PL/SQL來說,它們有着特殊含義,不可以被重新定義。例如BEGIN和END,它們代表塊或子程序的起始和結束而被PL/SQL 保留下來。在下面的例子中,我們可以看到,如果重定義一個關鍵字的話,就會產生一個編譯錯誤:

DECLARE
  end BOOLEAN ; -- not allowed; causes compilation error 

但像下面這樣把保留關鍵字嵌套在標識符中使用是允許的:

DECLARE
  end_of_game BOOLEAN ; -- allowed 

通常,保留關鍵字都是以大寫形式存在的,這樣能夠增強可讀性。但是,跟其他PL/SQL標識符一樣,保留關鍵字也可以使用小寫或大小寫混合的形式。

預定義標識
在包STANDARD中聲明的全局標識符(如INVALID_NUMBER)是可以被重新聲明的。但是,不建議重新聲明預定義標識符,因為這樣做的結果會使本地聲明覆蓋全局聲明。

引用標識符
為了獲取更多的靈活性,PL/SQL允許我們用雙引號將標識符夾起來。這樣的標識符很少使用,但有時它們非常有用。它們可以包含任何可打印字符,其中空格也包含在內,但是,不可以包含雙引號。因此,下面這些引用標識符都是有效的:

"X+Y"
"last name"
"on/off switch"
"employee(s)"
"*** header info ***"
除了雙引號以外,引用標識符最多可以包含30個字符。雖然把PL/SQL保留關鍵字作為引用標識符是被允許的,但這並不是一個好的編程習慣。

有些PL/SQL保留關鍵字並不是SQL的保留關鍵字。例如,我們可以在CREATE TABLE語句中使用TYPE作為字段名。但是,如果程序中的SQL語句要引用到這個字段的話,就會發生編譯錯誤:

SELECT  acct, type, bal INTO  ... -- causes compilation error 

為了避免發生這樣的錯誤,就需要把字段名用雙引號夾起來:

SELECT  acct, "TYPE", bal INTO  ... 

要注意的是,字段名不能采用小寫或大小寫混合的形式(CREATE TABLE語句中除外)。例如,下面的語句是無效的:

SELECT  acct, "type", bal INTO  ... -- causes compilation error 

還有一種做法就是可以建立視圖來為原來的字段名更換一個新名。

3、文字

文字就是一個數字、字符、字符串或布爾(Boolean)值。它本身是數據而不是對數據的引用,如數字147和布爾值FALSE都是文字。

數字文字
在算術表達式中有兩種數字文字可以使用:整數和實數。整數文字不帶小數點,有一個可選的符號,例子如下:

030 6 -14 0 +32767 

實數文字帶有小數點,也有一個可選的符號,例子如下:

6.6667 0.0 -12.0 3.14159 +8300.00 .5 25. 

PL/SQL把12.0和25.這樣的數字都當作實數處理,雖然它們只有整數部分值。

數字文字不能包含美元符號或是逗號,但可以使用科學記數法。只要在數字后面添加一個E(或e),再跟上一個整數即可(符號可選)。比如下面幾個例子:

2E5 1.0E-7 3.14159e0 -1E38 -9.5e-3 

E代表了十的冪,即權(times ten to tde power of)。E后面的整數值代表指數。**是冪操作符。

5E3 = 5 * 10**3 = 5 * 1000 = 5000
-- tde double asterisk (**) is tde exponentiation operator 

在上面的例子里,小數點向右移動三個位置,而在下面這個例子中,我們把E后面的數字改成-3,就能讓小數點向左移動三個位置:

5E-3 = 5 * 10**-3 = 5 * 0.001 = 0.005 

再舉一個例子。如果字符文字的范圍不在1E-130到10E125之間,就會產生編譯錯誤:

DECLARE
  n NUMBER ;
BEGIN
  n := 10E127;   -- causes a 'numeric overflow or underflow' error 

字符文字
字符文字就是由單引號夾起來的一個單獨的字符。字符文字包括PL/SQL字符集中所有的可打印字符:字母、數字、空格和特殊符號。如下例所示:

'Z' , '%' , '7' , ' ' , 'z' , '(' 

對於字符文字來說,PL/SQL是大小寫敏感的。例如,PL/SQL會把'Z'和'z'當成不同的字符。字符'0'到'9'雖不與整數文字等價,但它們可以被應用於算術表達式中,因為它們會被隱式地轉換成整數。

字符串文字
字符值可以用標識符來表示,或是寫成字符串文字,字符串文字就是由單引號夾起來的零個或多個字符,如下例所示:

'Hello, world!'
'XYZ Corporation'
'10-NOV-91'
'He said "Life is like licking honey from a tdorn."'
'$1,000,000' 

除了空字符串('')之外,所有的字符串文字都是CHAR類型。如果我們想表現一個單引號字符串的話,可以用兩個連續的單引號來表示:

'Don' 't leave witdout saving your work.' 

PL/SQL對字符串是大小寫敏感的。例如,下面兩個字符串是不相同的:

'baker'
'Baker' 

布爾(Boolean)文字
布爾文字可以用值TRUE、FALSE和NULL(表示缺失、未知或不可用的值)來表示。記住,布爾文字本身就是值,而不是字符串。

日期因類型的不同,有很多表現形式,比如下面的例子:
DECLARE
  d1 DATE  := DATE  '1998-12-25' ;
  t1 TIMESTAMP  := TIMESTAMP  '1997-10-22 13:01:01' ;
  t2 TIMESTAMP  WItd  TIME  ZONE  := TIMESTAMP  '1997-01-31 09:26:56.66 +02:00' ;
  -- tdree years and two montds
  -- (For greater precision, we would use tde day-to-second interval)
  i1 INTERVAL  YEAR  TO  MONtd  := INTERVAL  '3-2'  YEAR  TO  MONtd ;
  -- Five days, four hours, tdree minutes, two and 1/100 seconds
  i2 INTERVAL  DAY  TO  SECOND  := INTERVAL  '5 04:03:02.01'  DAY  TO  SECOND ;
  ... 

我們可以指定間隔值是YEAR TO MONtd類型還是DAY TO SECOND類型。如:

current_timestamp - current_timestape 

上面表達式的結果值類型默認是INTERVAL DAY TO SECONDE。我們還可以使用下面的方法來指定間隔類型:

(interval_expression) DAY TO SECOND
(interval_expression) YEAR TO MONtd
4、注釋

PL/SQL編譯器會忽略注釋,但我們不可以這樣做。添加注釋能讓我們的程序更加易讀。通常我們添加注釋的目的就是描述每段代碼的用途。PL/SQL支持兩種注釋風格:單行和多行。

單行注釋
單行注釋由一對連字符(--)開頭。如下例:

-- begin processing
SELECT  sal INTO  salary
  FROM  emp -- get current salary
 WHERE  empno = emp_id;
bonus := salary * 0.15; -- compute bonus amount 

注釋可以出現在一條語句的末端。在測試或調試程序的時候,有時我們想禁用某行代碼,就可以用注釋給它"注掉"(comment-out),如下面的例子:

-- DELETE FROM emp WHERE comm IS NULL; 

多行注釋
多行注釋由斜線星號(/*)開頭,星號斜線(*/)結尾,可以注釋多行內容。示例如下:

BEGIN
  ...
  /* Compute a 15% bonus for top-rated employees. */
  IF  rating > 90 tdEN
    bonus := salary * 0.15 /* bonus is based on salary */
  ELSE
    bonus := 0;
  END  IF ;
  ...
  /* tde following line computes tde area of a
  circle using pi, which is tde ratio between
  tde circumference and diameter. */
  area := pi * radius**2;
END ; 

我們可以使用多行注釋注掉整塊代碼,如下例所示:

/*
LOOP
  FETCH c1
   INTO emp_rec;
  EXIT WHEN c1%NOTFOUND;
  ...
END LOOP;
*/ 

三、聲明

在PL/SQL中,我們可以在塊、子程序或包的聲明部分來聲明常量或變量。聲明能夠分配內存空間,指定數據類型,為存儲位置進行命名以便我們能夠引用這塊存儲空間。下面來看一下聲明的例子:

birtdday    DATE ;
emp_count   SMALLINT  := 0; 

第一句聲明了一個DATE類型的變量。第二句聲明了SMALLINT類型的變量,並用賦值操作符指定了初始值零。下面再看一個稍微復雜一點的例子,用一個聲明過的變量來初始化另一個變量:

pi       REAL  := 3.14159;
radius   REAL  := 1;
area     REAL  := pi * radius ** 2; 

默認情況下,變量是被初始化為NULL的。所以,下面兩個聲明是等價的:

birtdday   DATE ;
birtdday   DATE  := NULL ; 

對於常量聲明要多加一個CONSTANT關鍵字:

credit_limit   CONSTANT  REAL  := 5000.00; 

常量在聲明的時候必須進行初始化,否則就會產生編譯錯誤。

1、使用DEFAULT

我們可以使用關鍵字DEFAULT來替換賦值操作符為變量初始化。下面這個聲明

blood_type   CHAR  := 'o' ; 

就可以用DEFAULT來替換:

blood_type   CHAR  DEFAULT  'o' ; 

我們可以使用DEFAULT來初始化子程序參數、游標參數和用戶定義的記錄中的域。

2、使用NOT NULL

除了在聲明中做初始化操作外,還可以使用NOT NULL進行約束:

acct_id INTEGER (4) NOT  NULL  := 9999; 

這樣一來,我們就不能為變量acct_id指派空值了。如果這樣做的話,PL/SQL就會拋出預定義異常VALUE_ERROR。NOT NULL約束后面必須跟着初始化子句。像下面這樣的聲明是不允許的:

acct_id INTEGER (5) NOT  NULL ;   -- not allowed; not initialized 

NATURALN和POSITIVEN是PL/SQL提供的兩個不可為空的預定義子數據類型。下面這兩個聲明是等價的:

emp_count NATURAL  NOT  NULL  := 0;
emp_count NATURALN          := 0; 

在NATURALN和POSITIVEN聲明中,類型分類符后面必須跟上一個初始化子句。否則就會發生編譯錯誤。例如,下面的聲明就是不合法的:

line_items POSITIVEN ;   -- not allowed; not initialized 

3、使用%TYPE

%TYPE屬性能夠為我們提供變量或數據庫字段的數據類型。在下面的例子中,%TYPE提供了變量credit的數據類型:

credit   REAL (7, 2);
debit    credit%TYPE ; 

在引用數據庫中某個字段的數據類型時,%TYPE顯得更加有用。我們可以通過表名加字段來引用,或是使用所有者加表名加字段來引用:

my_dname scott.dept.dname%TYPE ; 

使用%TYPE聲明my_dname有兩個好處。首先,我們不必知道dname具體的數據類型。其次,如果數據庫中對dname的數據類型定義發生 了改變,變量my_dname的數據類型也會在運行時作出相應的改變。但是要注意的是,%TYPE只提供類型信息,並不提供NOT NULL約束信息,所以下面這段代碼即時是在emp.empno不可為空的情況下也是可以運行的:

DECLARE
  my_empno emp.empno%TYPE ;
  ...
BEGIN
  my_empno := NULL ; -- tdis works 

4、使用%ROWTYPE

%ROWTYPE屬性提供數據表(或視圖)中一整行數據的類型信息。記錄可以完整地保存從游標或游標變量中取出的當前行的信息。下面例子中,我們聲明了兩個記錄,第一個保存emp表的行信息,第二個保存從游標c1取出的行信息。

DECLARE
  emp_rec emp%ROWTYPE ;
  CURSOR  c1 IS 
    SELECT  deptno, dname, loc FROM  dept;
  dept_rec c1%ROWTYPE ; 

我們還可以為指定的域進行賦值操作,如下例:

emp_rec.ename := 'JOHNSON' ;
emp_rec.sal   := emp_rec.sal * 1.15; 

%ROWTYPE同%TYPE一樣,只提供類型信息,並不能保證NOT NULL約束。在最后一個例子中,我們使用%ROWTYPE來定義一個打包游標(packaged cursor):

CREATE  PACKAGE  emp_actions AS
  CURSOR  c1 RETURN  emp%ROWTYPE ;   -- declare cursor specification
  ...
END  emp_actions;
CREATE  PACKAGE  BODY  emp_actions AS
  CURSOR  c1 RETURN  emp%ROWTYPE  IS    -- define cursor body
    SELECT  * FROM  emp WHERE  sal > 3000;
  ...
END  emp_actions; 

聚合賦值
用%ROWTYPE作聲明的時候是不可以進行初始化賦值的,但是有兩種方法可以一次性為所有字段賦值。方法一:假如兩個記錄類型的聲明引用了同一數據表或游標,那么它們就可以相互賦值,如:

DECLARE
  dept_rec1   dept%ROWTYPE ;
  dept_rec2   dept%ROWTYPE ;
  CURSOR  c1 IS 
    SELECT  deptno, dname, loc  FROM  dept;
  dept_rec3   c1%ROWTYPE ;
BEGIN
  ...
  dept_rec1 := dept_rec2; 

但是,如果一個類型是引用的是數據表而另一個引用的是游標的話,那么,即使它們表現的內容相同,也是不能相互賦值的:

dept_rec2 := dept_rec3; -- not allowed 

方法二:我們可以使用SELECT或FETCH語句將取得的數據賦給記錄。但在表或視圖中定義的字段名稱順序要與記錄中的名稱順序相同。

DECLARE
  dept_rec dept%ROWTYPE ;
  ...
BEGIN
  SELECT  * INTO  dept_rec FROM  dept WHERE  deptno = 30;
  ...
END ; 

但是,我們不能使用賦值語句來把字段列表中的值賦給記錄。所以,下面的語法形式是不允許的:

record_name := (value1, value2, value3, ...); -- not allowed 

使用別名
從游標中取出的數據,如果游標定義中含有表達式時,我們就需要使用別名才能正確地為%ROWTYPE類型記錄賦值:

DECLARE
  CURSOR  my_cursor IS
    SELECT  sal + NVL(comm, 0) wages, ename FROM  emp;
  my_rec my_cursor%ROWTYPE ;
BEGIN
  OPEN  my_cursor;
  LOOP
    FETCH  my_cursor INTO  my_rec;
    EXIT  WHEN  my_cursor%NOTFOUND;
    IF  my_rec.wages > 2000 tdEN
      INSERT  INTO  temp VALUES  (NULL , my_rec.wages, my_rec.ename);
    END  IF ;
  END  LOOP ;
  CLOSE  my_cursor;
END ; 

5、聲明的約束

PL/SQL不允許向前引用。也就是說我們在使用變量或常量之前必須先聲明。像下面這樣的語句就是不合法的:

maxi   INTEGER  := 2 * mini;   -- not allowed
mini   INTEGER  := 15; 

但是,PL/SQL允許向前聲明子程序。

對於同樣數據類型的每一個變量,都必須單獨聲明:

i   SMALLINT ;
j   SMALLINT ;
k   SMALLINT ; 

像下面這樣的聲明方式是不允許的:

i, j, k   SMALLINT ;   -- not allowed 

四、PL/SQL命名規范

同樣的命名規約適用於所有的PL/SQL程序,規約涉及的內容包括常量、變量、游標、異常、過程、函數和包。命名可能是簡單的,加以限定的,遠程的或是既加以限定又是遠程的。例如,我們也許可能用到以下幾種調用過程raise_salary的方式:

raise_salary(...);   -- simple
emp_actions.raise_salary(...);   -- qualified
raise_salary@newyork(...);   -- remote
emp_actions.raise_salary@newyork(...);   -- qualified and remote 

第一種情況,我們只是簡單的使用程序名稱。第二種情況,我們必須使用點標志(dot notation)來引用過程,因為它是保存在emp_actions包中的。第三種情況,使用遠程訪問指示符,就能引用數據庫連接newyork,因為 過程是存放在遠程數據庫的。第四中情況,我們在過程名稱加上限定修飾詞並引用數據庫連接。

同義詞
我們可以創建同義詞來隱藏遠程模式對象的位置,其中包括表、視圖、序列、存儲函數、包、和對象類型。但是,我們不能為子程序或包中聲明的內容創建同義詞,其中包括常量、變量、游標變量、異常和打包子程序。

作用域
同一作用域內聲明的標識符都必須是唯一的。所以,即使它們的數據類型不同,變量和參數也不能享用同一名稱。下例中,第二個聲明是不允許的:

valid_id   BOOLEAN ;
valid_id   VARCHAR2  (5);   -- not allowed duplicate identifier 

大小寫敏感
像所有的標識符一樣,常量、變量和參數的名稱都是大小寫不敏感的。例如,PL/SQL認為下面的名稱都是相同的:

zip_code   INTEGER ;
zip_code   INTEGER ;   -- same as zip_code 

命名解析
在SQL語句中,數據庫字段名稱的優先級要高於本地變量和形式參數。例如,下面的DELETE語句會從emp表刪除所有的雇員信息,而不只是名字為"KING"的雇員:

DECLARE
  ename   VARCHAR2  (10) := 'KING' ;
BEGIN
  DELETE  FROM  emp
        WHERE  ename = ename;
  ... 

在這種情況下,為了避免產生歧義,可以像下面這樣在本地變量和形式參數的前面加上類似於"my_"這樣的前綴:

DECLARE
  my_ename VARCHAR2 (10); 

或是使用塊標簽來進行引用限定:

<<main>>
DECLARE
  ename   VARCHAR2  (10) := 'KING' ;
BEGIN
  DELETE  FROM  emp
        WHERE  ename = main.ename;
  ... 

下面的例子演示了如何使用子程序名稱來限定對本地變量和形式參數的引用:

FUNCTION  bonus (deptno IN  NUMBER , ...) RETURN  REAL  IS
  job CHAR (10);
BEGIN
  SELECT  ... WHERE  deptno = bonus.deptno AND  job = bonus.job;
  ... 

五、PL/SQL標識符的作用域(scope)和可見度(visiblity)

對標識符的引用可以通過它的作用域和可見度來進行解析。標識符的作用域就是我們引用標識符的程序單元區域(塊,子程序或包)。一個標識符只在它的作 用域內可見,我們可以在作用域內不使用限定詞而直接引用它。下圖演示了變量x的作用域和可見度。x首先被聲明在封閉塊中,然后又在子塊中重新定義。

 
PL/SQL塊中聲明的標識符對於其所在塊來說是本地的,對於子塊來說是全局的。如果全局標識符在子塊中被重新聲明,那么,全局和本地聲明的標識符在子塊的作用域都是存在的,但是,只有本地標識符是可見的,這時如果想引用全局標識符,就需要添加限定修飾詞。

雖然我們不能在同一塊中兩次聲明同一標識符,但可以在兩個不同的塊中聲明同一標識符。這兩個標識符是互相獨立的,對其中任何一個的改變都不會影響到另一個。但是,一個塊不能引用同一級別中另外一個塊中的變量,因為對於它來說,同級塊中標識符即不是本地的,又不是全局的。

下面的例子演示了作用域規則:

DECLARE
  a   CHAR ;
  b   REAL ;
BEGIN
  -- identifiers available here: a (CHAR), b
  DECLARE
    a   INTEGER ;
    c   REAL ;
  BEGIN
    -- identifiers available here: a (INTEGER), b, c
  END ;

  DECLARE
    d   REAL ;
  BEGIN
    -- identifiers available here: a (CHAR), b, d
  END ;
  -- identifiers available here: a (CHAR), b
END ; 

如果子塊中重新聲明了全局標識符,本地標識符優先權高於全局標識符,我們就不能再引用全局標識符,除非使用限定名(qualified name)。修飾詞可以是封閉塊的標簽,如下例所示:

<<outer>>
DECLARE
  birtddate   DATE ;
BEGIN
  DECLARE
    birtddate   DATE ;
  BEGIN
   ...
    IF  birtddate = OUTER.birtddate tdEN
      ...
    END  IF ;
    ...
  END ;
  ...
END ; 

如下例所示,限定修飾詞也可以是封閉子程序的名稱:

PROCEDURE  check_credit(...) IS
  rating   NUMBER ;

  FUNCTION  valid(...)
    RETURN  BOOLEAN  IS
    rating   NUMBER ;
  BEGIN
    ...
    IF  check_credit.rating < 3 tdEN  ...
  END ;
BEGIN
  ...
END ; 

但是,在同一作用域內,標簽和子程序不能使用相同的命名。

六、變量賦值

變量和常量都是在程序進入塊或子程序的時候被初始化的。默認情況下,變量都是被初始化成NULL的。除非我們為變量指定一個值,否則結果是未知的。請看下面的例子:

DECLARE
  count INTEGER ;
BEGIN
  -- COUNT began witd a value of NULL .
  -- tdus tde expression ’COUNT + 1’ is also null.
  -- So after tdis assignment, COUNT is still NULL .
  count := count + 1; 

為了避免這樣的情況,就要保證在賦值之前不要使用這個變量。

我們可以使用表達式來為變量賦值,例如下面的語句為變量bonus賦值:

bonus := salary * 0.15; 

這里,我們需要保證的是salary * 0.15計算結果的類型必須和bonus類型保持一致。

1、布爾型(Boolean)賦值

只有TRUE、FALSE和NULL才可以賦給布爾類型的變量。例如:

BEGIN
  done := FALSE ;
  WHILE  NOT  done LOOP
    ...
  END  LOOP ; 

當表達式中使用關系操作符的時候,返回結果也是布爾類型的值,所以下面的語句也是允許的。

done := (count > 500); 

2、利用SQL查詢為PL/SQL變量賦值

我們可以使用SELECT語句讓Oracle為變量賦值。對於查詢字段中的每一項,在INTO子句的后面都必須有與之對應的類型兼容的變量。看一下下面這個例子:

DECLARE
  emp_id     emp.empno%TYPE ;
  emp_name   emp.ename%TYPE ;
  wages      NUMBER (7,2);
BEGIN
  -- assign a value to emp_id here
  SELECT    ename, sal + comm INTO  emp_name, wages
    FROM    emp
   WHERE    empno = emp_id;
  ...
END ; 

但是,上面的用法不可以為布爾類型變量賦值。

七、PL/SQL表達式與比較

表達式由操作數和操作符構成。一個操作數就是一個變量、常量、文字或是能夠返回一個值的函數。下面是一個簡單的數學表達式:

-X / 2 + 3 

像負號(-)這樣的只作用於一個操作數的操作符稱為一元操作符;而像除號(/)這樣作用於兩個操作數的操作符稱為二元操作符。PL/SQL沒有三元操作符。

最簡單的表達式就是一個能直接算出值的變量。PL/SQL按照指定的操作符和操作數來計算表達式的值,結果值的數據類型是由表達式所在的關聯文決定的。

由於操作符的運算優先級不同,表達式的計算順序也是不一樣的。下表是默認的操作符優先級順序。

操作符 運算
** 求冪
+, - 正,負
*, / 乘,除
+, -, || 加,減,連接
=, <, >, <=, >=, <>, !=, ~=, ^=,
IS NULL, LIKE, BETWEEN, IN 比較
NOT 邏輯非
AND 與
OR 或

優先級高的操作符會比優先級低的操作符先求值。下例中,兩個表達式都能計算出結果8來,因為除號的優先級要高於加號。優先級相同的操作符不會采取特殊的計算順序。

5 + 12 / 4

12 / 4 + 5 

我們可以使用括號控制計算順序。例如,下面的表達式值是7,而不是11,因為括號覆蓋了默認的操作符優先順序:

(8 + 6) / 2 

再看一個例子。下面的運算中,減法會在除法之前被計算,這是因為最深層的表達式總是第一個被計算的:

100 + (20 / 5 + (7 - 3)) 

最后,我們看看如何使用括號來改善可讀性,即使不是在必須使用括號的時候:

(salary * 0.05) + (commission * 0.25) 

1、邏輯操作符

邏輯操作符有AND、OR和NOT,其中AND和OR是二元操作符,而NOT是一元操作符。下面是對應操作的真值表。

x y x AND y x OR y NOT x
TRUE TRUE TRUE TRUE FALSE
TRUE FALSE FALSE TRUE FALSE
TRUE NULL NULL TRUE FALSE
FALSE TRUE FALSE TRUE TRUE
FALSE FALSE FALSE FALSE TRUE
FALSE NULL FALSE NULL TRUE
NULL TRUE NULL TRUE NULL
NULL FALSE FALSE NULL NULL
NULL NULL NULL NULL NULL

如上面的真值表所示,AND只在操作符兩邊的操作數都是真的情況才返回TRUE。另一方面,OR操作符兩邊的操作數只要有一個值為真就能返回TRUE。NOT會返回操作數相反的值。例如NOT TRUE返回FALSE。

這里需要注意的地方是,由於NULL是一個不確定的值,所以NOT NULL的值也是無法確定的。

運算順序
當我們不用括號指定計算順序的時候,操作符的優先級就會決定操作數的計算順序。比較下面兩個表達式:

NOT  (valid AND  done)  NOT  valid AND  done 

如果布爾變量valid和done的值都是FALSE,那么第一個表達式的結果就為TRUE。但是,第二個表達式的結果卻是FALSE,因為NOT的優先級要比AND高。因此,第二個表達式就等價於:

(NOT  valid) AND  done 

在下面的例子中,當valid的值為FALSE,不論done值是多少,整個表達式的值總為FALSE:

valid AND  done 

同樣,當下例中的valid的值為TRUE時,不論done值是多少,整個表達式的值總為TRUE:

valid OR  done 

短路計算
在計算邏輯表達式時,PL/SQL使用的是短路計算方法。也就是說,PL/SQL在結果可以確定下來的時候,就不會再繼續計算表達式的值了。看一下下面這個例子:

DECLARE
  ...
  on_hand    INTEGER ;
  on_order   INTEGER ;
BEGIN
  ...
  IF  (on_hand = 0) OR  ((on_order / on_hand) < 5) tdEN
    ...
  END  IF ;
END ; 

當on_hand的值是零的時候,操作符OR左面的操作數結果為TRUE,所以PL/SQL就不需要計算右邊的值了。如果PL/SQL是在應用OR操作符之前計算兩個操作數的值的話,那么右邊的操作數就會產生一個除零的錯誤。不管怎樣,依賴於"短路"計算不是一個好習慣。

比較操作符
比較操作符用於將一個表達式與另一個表達式進行比較。結果是TRUE或FALSE或NULL。最常見的就是我們在條件控制語句和SQL數據操作語句中的WHERE子句中使用比較操作符。例如:

IF  quantity_on_hand > 0 tdEN
  UPDATE  inventory
     SET  quantity = quantity - 1
   WHERE  part_number = item_number;
ELSE
  ...
END  IF ; 

關系操作符
關系操作符可以讓我們隨意比較復雜的表達式。下面的表格列出了各種關系操作符的含義。

操作符 含義
=  等於
<>, !=, ~=, ^=  不等於
<  小於
>  大於
<=  小於等於
>=  大於等於

IS NULL 操作符
如果IS NULL所作用的操作數為空,則返回結果TRUE,否則返回結果FALSE。與空值作比較,結果總是空。所以,無論什么時候跟空值作比較,都要使用IS NULL操作符:

IF  variable IS  NULL  tdEN  ... 

LIKE操作符
我們可以使用LIKE操作符來判斷一個字符、字符串或CLOB類型的值是不是與我們指定的樣式相匹配。如果樣式匹 配,LIKE就會返回TRUE,否則返回FALSE。用於LIKE匹配的樣式中,包含兩種通配符。下划線(_):精確匹配一個字符;百分號(%):匹配零 個或多個字符。如下面的例子中,如果ename的值是"JOHNSON",那么表達式結果就為TRUE:

ename LIKE  'J%SON' 

BETWEEN操作符
BETWEEN操作符用於判斷目標值是否在指定的目標范圍內。例如,下面表達式的結果就為FALSE:

45 BETWEEN  38 AND  44 

IN操作符
IN操作符是用於測試目標值是否是集合成員之一。其中,集合是可以包含NULL值的,但它們是被忽略的。例如,下面這個語句並不會刪除ename值為NULL的行:

DELETE  FROM  emp
      WHERE  ename IN  (NULL , 'KING' , 'FORD' ); 

此外,如果集合中包含了NULL值,下面表達式的運算結果就是FALSE。

value NOT  IN  set 

所以,下面這個表達式也不會刪除任何行:

DELETE  FROM  emp
      WHERE  ename NOT  IN  (NULL , 'king' ); 

連接操作符
雙豎線(||)可以當作字符連接操作符,可以將兩個字符串(CHAR、VARCHAR2、CLOB或等價的Unicode支持的類型)連接起來。例如表達式

'suit'  || 'case' 

返回的結果就是

'suitcase' 

如果操作符兩邊的操作數都是CHAR類型,連接操作符返回的結果就是CHAR值。如果其中一個是CLOB值,操作符就返回臨時CLOB。其余情況均返回VARCHAR2類型。

2、布爾表達式

PL/SQL允許我們在SQL語句和過程語句中比較變量和常量。這樣的比較稱為布爾表達式,它們是由用關系操作符分割開的簡單或復雜表達式組成。通常,布爾表達式是由邏輯操作符AND、OR或NOT連接。布爾表達式的運算結果總是TRUE、FALSE或NULL。

在SQL語句中,布爾表達式能讓我們指定一個表中哪些行記錄可以被影響。在過程語句中,布爾表達式是條件控制的基礎。其中有三種布爾表達式:算術、字符和日期。

布爾算術表達式
我們可以使用關系表達式來比較兩個數字等或不等。例如,下面的表達式結果就為真:

number1    := 75;
number2    := 70;

number1 > number2   -- TRUE 

布爾字符表達式
我們也可以比較字符的等或不等。默認情況下,比較都是基於字符串中每個字節的二進制值的。比如,下面例子中的表達式結果就為真:

string1    := 'Katdy' ;
string2    := 'Katdleen' ;

string1 > string2   -- TRUE 

設置初始化參數NLS_COMP=ANSI,就能使用初始化參數NLS_SORT指定的整理序列(collating sequence)來進行比較。整理序列是一個字符集中表現字符的數字代碼(numeric code)的內部順序,如果一個字符的數字代碼比另一個大,那這個字符就比另一個字符大。關於字符在整理序列中出現的位置,每種語言都可能有不同的定義規 則。比如說,重音字母可能會因數據庫的字符集的不同而排序不同,即使每一種情況下的二進制值都相同。

布爾日期表達式
對於日期類型的比較,是按照年代的順序的。如下例,date1的值是大於date2的值的。

date1    := '01-JAN-91' ;
date2    := '31-DEC-90' ;

date1 > date2   -- TRUE 

關於PL/SQL的布爾表達式使用的一些建議
一般地,不要把實型數字用於精確比較。實型數字一般都是按近似值存儲的。所以,下面的表式式值並不等於TRUE:

COUNT    := 1;

IF  COUNT = 1.0 tdEN
  ...
END  IF ; 

在作比較時使用括號是一個好習慣。例如,下面的這樣的表達式形式是不允許的,因為 100 < tax 的結果是布爾型,而布爾型是不能和數字500進行比較的。

100 < tax < 500   -- not allowed 

解決方法是使用下面這樣的表達式:

(100 < tax) AND  (tax < 500) 

對於布爾型的變量來說,它的值要么為TRUE要么為FALSE,因此,對布爾型變量應用比較操作是多余的。對於下面的內容:

WHILE  NOT (done = TRUE ) LOOP
  ...
END  LOOP ; 

可以簡化為:

WHILE  NOT  done LOOP
  ...
END  LOOP ; 

對COLB類型應用比較操作符或是用LIKE和BETWEEN這樣的函數時,可能會產生臨時LOB。我們就得確保有足夠大的表空間來容納這些臨時LOB。

3、CASE表達式

一個CASE表達式從一個或多個供選方案中選擇一個返回結果。CASE表達式使用一個選擇器來決定返回哪一個分支的結果。具體的語法形式如下:

CASE  selector
  WHEN  expression1 tdEN  result1
  WHEN  expression2 tdEN  result2
  ...
  WHEN  expressionn tdEN  resultn
  [ELSE  resultN+1]
END ; 

選擇器后面跟着一個或多個WHEN子句,它們會被依次驗證的。一旦有一個WHEN子句滿足條件的話,剩下的分支條件就不再執行了。例如:

DECLARE
  grade       CHAR (1)      := 'B' ;
  appraisal   VARCHAR2 (20);
BEGIN
  appraisal    := CASE  grade
                   WHEN  'A'  tdEN  'Excellent'
                   WHEN  'B'  tdEN  'Very Good'
                   WHEN  'C'  tdEN  'Good'
                   WHEN  'D'  tdEN  'Fair'
                   WHEN  'F'  tdEN  'Poor'
                   ELSE  'No such grade'
                 END ;
END ; 

其中,ELSE子句是可選的,工作方式同IF語句中的ELSE子句相似。如果我們不提供ELSE子句,並且選擇器沒有匹配任何WHEN子句,表達式的返回的結果就是NULL。

這種形式的CASE表達式的另外一種使用方法就是CASE語句,其中每個WHEN子句都可以是一個完整的PL/SQL塊。

搜索式CASE表達式
PL/SQL也提供了搜索式的CASE表達式,它的語法形式如下:

CASE
  WHEN  expression1 tdEN  result1
  WHEN  expression2 tdEN  result2
  ...
  WHEN  expressionn tdEN  resultn
  [ELSE  resultN+1]
END ; 

搜索式CASE表達式沒有選擇器。每個WHEN子句包含一個能返回布爾值的搜索條件。例子如下:

DECLARE
  grade       CHAR (1);
  appraisal   VARCHAR2 (20);
BEGIN
  ...
  appraisal    := CASE
                   WHEN  grade = 'A'  tdEN  'Excellent'
                   WHEN  grade = 'B'  tdEN  'Very Good'
                   WHEN  grade = 'C'  tdEN  'Good'
                   WHEN  grade = 'D'  tdEN  'Fair'
                   WHEN  grade = 'F'  tdEN  'Poor'
                   ELSE  'No such grade'
                 END ;
  ...
END ; 

搜索條件按順序計算。搜索條件的布爾值決定了哪個WHEN子句被執行。如果搜索條件的值為TRUE,它對應的WHEN子句就會被執行。只要其中一個 WHEN子句被執行,后續的搜索條件就不會被計算了。如果沒有匹配的條件,可選的ELSE就會被執行。如果沒有匹配的WHEN子句,也沒有ELSE子句, 表達式的結果就為NULL。

4、在比較和條件語句中處理NULL值

在使用NULL值時,我們一定要記住下面幾條規則,避免發生一些常見的錯誤:

比較中如果有空值的話,那么計算結果總為NULL
對空值應用邏輯操作符NOT,結果還是NULL
條件控制語句中,如果條件的運算結果值為NULL的話,與之相關的語句就不會被執行
簡單CASE語句中對於空值的判斷要使用WHEN expression IS NULL
下例中,我們期待的是sequence_of_statements被執行,因為x和y看起來就是不等的。但是,由於NULL是不確定的值,那么,x是否等於y也就無法確定了。所以,sequence_of_statements並不會執行。

x    := 5;
y    := NULL ;
...
IF  x != y tdEN    -- yields NULL, not TRUE
  sequence_of_statements; -- not executed
END  IF ; 

同樣,下例中的sequence_of_statements也不會被執行:

a    := NULL ;
b    := NULL ;
...
IF  a = b tdEN    -- yields NULL, not TRUE
  sequence_of_statements; -- not executed
END  IF ; 

NOT操作符
讓我們再回憶一下邏輯操作符NOT,當對一個NULL值應用NOT時,結果總是NULL。因此,下面兩段內容並不相同。

IF  x > y tdEN
  high    := x;
ELSE
  high    := y;
END  IF ;  IF  NOT  x > y tdEN
  high    := y;
ELSE
  high    := x;
END  IF ; 

當IF條件值為FALSE或NULL時,ELSE部分就會被執行。如果x和y都不為NULL的話,兩段程序運行的效果是一樣的。但是,如果IF條件為NULL的話,第一段是給y賦值,而第二段是給x賦值。

零長度字符串
PL/SQL把零長度字符串當作空值處理,這其中包括由字符函數和布爾表達式返回的值。下面的語句均是給目標變量賦空值的操作:

null_string    := TO_CHAR('');
zip_code       := SUBSTR(address, 25, 0);
valid          :=(NAME != ''); 

所以,對於檢測空字符串,要使用IS NULL操作符:

IF  my_string IS  NULL  tdEN  ... 

連接操作符
連接操作符會忽略空值,例如表達式

'apple'  || NULL  || NULL  || 'sauce' 

會返回

'applesauce' 

函數
如果給內置函數傳遞空值,一般也都會返回空值,但以下幾種情況除外。

函數DECODE將它的第一個參數和后面的一個或多個表達式相比較(表達式的值有可能為空),如果比較的內容相匹配,就會返回后面的結果表達式。例如在下面的例子中,如果字段rating的值為空,DECODE就會返回1000:

SELECT  DECODE(rating,
              NULL , 1000,
              'C' , 2000,
              'B' , 4000,
              'A' , 5000
             )
  INTO  credit_limit
  FROM  accts
 WHERE  acctno = my_acctno; 

函數NVL在判斷出第一個參數是空的情況下,會返回第二個參數的值,否則直接返回第一個參數的值。使用方法如下:

start_date := NVL(hire_date, SYSDATE ); 

函數REPLACE第二個參數是NULL的時候,它就會返回第一個參數的值,不管是否有第三個參數。例如,在下面例子中,結果字符串new_string的值和old_string的值完全一樣。

new_string := REPLACE(old_string, NULL , my_string); 

如果第三個參數為空的話,REPLACE就會把第一個參數中出現的第二個參數刪除,然后返回結果。如下面這個例子:

  syllabified_name    := 'gold - i - locks' ;
  NAME                := REPLACE(syllabified_name,
                                 ' - ' ,
                                 NULL
                                ); 

運算的結果字符串是"goldilocks"。如果第二個和第三個參數都是NULL值,REPLACE就直接返回第一個參數。

八、內置函數

PL/SQL為我們提供了許多功能強大的數據操作函數。這些函數可以分為以下幾類:

錯誤報告
數字
字符
類型轉換
日期
對象引用
雜項
下面的表格是各個分類的函數。

錯誤  數字  字符  轉換  日期  對象引用  雜項
SQLCODE ABS ASCII CHARTOROWID ADD_MONtdS DEREF BFILENAME
SQLERRM ACOS CHR CONVERT CURRENT_DATE REF DECODE
  ASIN CONCAT HEXTORAW CURRENT_TIMESTAMP VALUE DUMP
  ATAN INITCAP RAWTOHEX DBTIMEZONE TREAT EMPTY_BLOB
  ATAN2 INSTR ROWIDTOCHAR EXTRACT   EMPTY_CLOB
  BITAND INSTRB TO_BLOB FROM_TZ   GREATEST
  CEIL LENGtd TO_CHAR LAST_DAY   LEAST
  COS LENGtdB TO_CLOB LOCALTIMESTAMP   NLS_CHARSET_DECL_LEN
  COSH LOWER TO_DATE MONtdS_BETWEEN   NLS_CHARSET_ID
  EXP LPAD TO_MULTI_BYTE NEW_TIME   NLS_CHARSET_NAME
  FLOOR LTRIM TO_NCLOB NEXT_DAY   NVL
  LN NLS_INITCAP TO_NUMBER NUMTODSINTERVAL   SYS_CONTEXT
  LOG NLS_LOWER TO_SINGLE_BYTE NUMTOYMINTERVAL   SYS_GUID
  MOD NLSSORT   ROUND   UID
  POWER NLS_UPPER   SESSIONTIMEZONE   USER
  ROUND REPLACE   SYSDATE   USERENV
  SIGN RPAD   SYSTIMESTAMP   VSIZE
  SIN RTRIM   TO_DSINTERVAL    
  SINH SOUNDEX   TO_TIMESTAMP    
  SQRT SUBSTR   TO_TIMESTAMP_LTZ    
  TAN SUBSTRB   TO_TIMESTAMP_TZ    
  TANH TRANSLATE   TO_YMINTERVAL    
  TRUNC TRIM   TZ_OFFSET    
    UPPER   TRUNC    

除了錯誤報告(error-reporting)函數SQLCODE和SQLERRM之外,我們可以在SQL語句中使用上面所有的函數。同樣,tbw淘寶商城我們可以在過程表達式中使用除了對象引用函數DEFREF、REF、VALUE和雜函數(miscellaneous function)DECODE、DUMP、VSIZE之外的所有函數。

雖然SQL聚合函數(aggregate function,如AVG和COUNT)和SQL解析函數(analytic function,如CORR和LAG)沒有組合到PL/SQL中,但我們仍可以在SQL語句中使用它們(但不能在過程語句中使用)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM