1. 程式人生 > >PL\SQL使用者指南與參考2 轉載

PL\SQL使用者指南與參考2 轉載

一、字符集

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

  1. 大小寫字母(A-Z和a-z)
  2. 數字(0-9)
  3. 符號( ) + - * / < > = ! ~ ^ ; : . ’ @ % , " # $ & _ | { } ? [ ]
  4. 製表符、空格和回車符

PL/SQL對大小寫不敏感,所以,除了在字串和字元中,小寫字母和它對應的大寫字母是等價的。

二、詞法單元

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

  1. 分隔符(簡單符號和複合符號)
  2. 識別符號,其中包括關鍵字
  3. 文字
  4. 註釋

為改善可讀性,我們可以用空格將詞法單元分隔開。實際上,我們必須將相鄰的兩個識別符號用空格或標點符號隔開。下面這樣的寫法是不允許的,因為關鍵字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程式中的常量、變數、異常、遊標、遊標變數、子程式和包命名。下面是一些識別符號的例子:

  1. X
  2. t2
  3. phone#
  4. credit_limit
  5. LastName
  6. oracle$number

識別符號可以由字母、數字、美元符號($)、下劃線(_)和數字符號(#)組成。而像連字元(-)、斜線(/)等符號都是不允許使用的。如下例:

  1. mine&yours -- 不允許使用連字元(not allowed because of ampersand)
  2. debit-amount -- 不允許使用連字元(not allowed because of hyphen)
  3. on/off -- 不允許使用斜線(not allowed because of slash)
  4. user id -- 不允許使用空格(not allowed because of space)

而使用美元符號、下劃線和數字符號都是允許的:

  1. money$$$tree
  2. SN##
  3. try_again_

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

  1. lastname
  2. LastName -- 與lastname相同
  3. 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允許我們用雙引號將識別符號夾起來。這樣的識別符號很少使用,但有時它們非常有用。它們可以包含任何可列印字元,其中空格也包含在內,但是,不可以包含雙引號。因此,下面這些引用識別符號都是有效的:

  1. "X+Y"
  2. "last name"
  3. "on/off switch"
  4. "employee(s)"
  5. "*** 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。我們還可以使用下面的方法來指定間隔型別:

  1. (interval_expression) DAY TO SECOND
  2. (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
[email protected](...);   -- remote
[email protected](...);   -- 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 = TRUELOOP
  ...
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值時,我們一定要記住下面幾條規則,避免發生一些常見的錯誤:

  1. 比較中如果有空值的話,那麼計算結果總為NULL
  2. 對空值應用邏輯操作符NOT,結果還是NULL
  3. 條件控制語句中,如果條件的運算結果值為NULL的話,與之相關的語句就不會被執行
  4. 簡單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'
  • 函式

相關推薦

PL\SQL使用者指南參考2 轉載

一、字符集 在PL/SQL程式中,允許出現的字符集包括: 大小寫字母(A-Z和a-z) 數字(0-9) 符號( ) + - * / < > = ! ~ ^ ; : . ’ @ % , " # $ & _ | { } ? [ ] 製表符、空格和回車符 PL/SQL對大小寫不

Oracle PL SQL專家指南 高級PL/SQL解決方安案的設計開發

pad tkprof microsoft ext michael 加密 sql腳本 pro 體系結構 下載地址:網盤下載 內容介紹編輯本書所包含的大量信息可將您的編程技術提高到一個新的水平。您將學習編寫動態PL/SQL程序和Oracle數據庫接口、執行復雜計算,以及使用高級

《Oracle PL/SQL開發指南》學習筆記1——Oracle PL/SQL程式開發概覽

本章內容: 1. PL/SQL的歷史和背景 2. Oracle開發架構   知識點: 1. SQL和PL/SQL的關係: The SQL language is the interface to the Oracle Database 12c database

SQL學習指南(第2版修訂版)

網站 更多書籍點選進入>> CiCi島 下載 電子版僅供預覽及學習交流使用,下載後請24小時內刪除,支援正版,喜歡的請購買正版書籍 電子書下載(皮皮雲盤-點選“普通下載”) 購買正版 封頁 內容簡介 本書全面系統地介紹了SQL

《Oracle PL/SQL開發指南》學習筆記31——原始碼除錯——函式和過程(第四部分,物件表函式,result_cache子句)

  建立一個物件表函式有三個步驟: 1. 定義記錄結構為物件型別 2. 定義集合 3. 定義一個函式來展示如何從PL/SQL上下文向SQL上下文返回集合   1. 建立基本的SQL使用者自定義型別(UDT) 注意:發現竟然不能使用distinct關

《Oracle PL/SQL開發指南》學習筆記31——原始碼除錯——函式和過程(第三部分,並行查詢及管道函式)

  1. PARALLEL_ENABLE子句(啟用並行查詢以提高效能) 首次接觸,學習一下: PARALLEL_ENABLE lets you designate a function to support parallel query capabilities. This

《Oracle PL/SQL開發指南》學習筆記31——原始碼除錯——函式和過程(第二部分,函式)

  1. 命名塊函式原型 [{EDITIONALBE | NONEDITIONALBE}] FUNCTION function_name ( parameter [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype [, parame

《Oracle PL/SQL開發指南》學習筆記31——原始碼除錯——函式和過程(第一部分,函式呼叫表示法)

這節很基礎,卻發現了Oracle的可愛之處,一個函式呼叫就提供了這麼多選項,學起來真夠累的!   1. 在PL/SQL中呼叫函式表示法  SQL> /* Formatted on 2018/12/4 0:08:00 (QP5 v5.256.13226.355

《Oracle PL/SQL開發指南》學習筆記30——原始碼除錯——錯誤管理(第四部分,utl_call_stack包中的函式)

utl_call_stack包中的函式整理如下: Package Function Description backtrace_depth Returns the number of backtrace items in

《Oracle PL/SQL開發指南》學習筆記19——Control Structures(Review Section,Mastery Check)

這章是programming的核心所在。 Conditional Statements Review Section This section has described the following points about conditional compilation

《Oracle PL/SQL開發指南》學習筆記26——觸發器(Triggers)(章節回顧、測試)(第二部分)

複合觸發器(Compound Triggers) Review Section This section has described the following points about the Oracle Database 12c compound database

oracle PL/SQL-FOR UPDATE FOR UPDATE OF的區別

PL/SQL-FOR UPDATE 與 FOR UPDATE OF的區別 資料庫 oracle for update of   和   for update區別     select * from TTable1 for update 鎖定表的所有行,只能讀不能寫 2

《Oracle PL/SQL開發指南》學習筆記28——原始碼除錯——PL/SQL基礎知識(第三部分)

1. 變數賦值時(隱式)強制型別轉換 (讓我想起了將近二十年前學C語言時的場景) SQL> edit Wrote file afiedt.buf 1 DECLARE 2 lv_input INTEGER; 3 BEGIN 4 lv_inp

《Oracle PL/SQL開發指南》學習筆記27——動態SQL(Dynamic SQL)(章節回顧、測試)

動態SQL語句是一種強大的技術,通過它可以在程式執行時寫和執行查詢,修改DDL和DML語句。 本地動態SQL(Native Dynamic SQL (NDS)) Review Section This section has described the following

PL/SQL簡介基本語法

rep round 子程序 package 符號 編程語言 類型 運算符 授權 PL/SQL的簡介: PLSQL 是Oracle公司在SQL基礎上進行擴展而成的一種過程語言。PLSQL提供了典型的高級語言特 性,包括封裝,例外處理機制,信息隱藏,面向對象等;並

PL/SQL學習筆記_03_存儲函數存儲過程

employ span function aps 學習 lsi acl 操作 img ORACLE 提供可以把 PL/SQL 程序存儲在數據庫中,並可以在任何地方來運行它。這樣就叫存儲過程或函數。 存儲函數:有返回值,創建完成後,通過select function() f

Oracle或PL/SQL自動斷開連接解決參考

where dba ring 文件 mon connect 資源文件 時間值 資源配置 ORACLE自動斷開數據庫連接解決辦法 方法一、直接修改資源配置文件 分三個步驟在sqlplus環境下完成。 第一步,查詢資源文件,找到CONNECT_TIM

PL/SQL重新編譯包無反應案例2

測試環境 編譯 導致 執行 ssi 由於 targe 發現 code 在這篇"PL/SQL重新編譯包無反應"裏面介紹了編譯包無反應的情況,今天又遇到一起案例, 在測試環境中,一個包的STATUS為INVALID,重新編譯時,一直處於編譯狀態,檢查發現下面兩條因素都不存在:

Oracle之PL/SQL編程_數據類型定義變量和常量

oracle 數據類型 變量 常量-----------------------------------基本數據類型-----------------------------------1.數值類型NUMBER(P,S)參數 P 表示精度,參數 S 表示刻度範圍。精度是指數值中所有有效數字的個數,而刻度範圍是

[轉載]Oracle PL/SQL之LOOP循環控制語句

com 範圍 toolbar 得到 end 執行權 增加 oracl 序列 在PL/SQL中可以使用LOOP語句對數據進行循環處理,利用該語句可以循環執行指定的語句序列。常用的LOOP循環語句包含3種形式:基本的LOOP、WHILE...LOOP和FOR...LOOP。