---
# System prepended metadata

title: PL/SQL Oracle
tags: [SQL]

---

# PL/SQL Oracle
> SQL在本質上缺乏對輸出結果的程序化控制。
> 它沒有陣列的處理、迴圈的結構以及其他程式語言的功能。
> 
> 為符合實際需要，Oracle於是提供內建的程式語言，稱為
> 結構化查詢語言的程序化語言(Procedural Language for SQL)

> 於SQL*Plus 鍵入程式
> 
> 若執行不成功，可鍵入show errors將顯示執行期間
> 所產生之錯誤。
> 
> 一樣以edit命令編輯修改程式。
> 
> 欲取出輸出結果，Oracle提供一內建的package稱為dbms_output， 在程式中加入dbms_output。
> put_line 指令後便可出現結果。
> 
> 若結果沒出現，輸入set serveroutput on 來開啟螢幕輸出功能。

#### PL/SQL 結構

```SQL=
[DECLARE]
-- 將變數放在這裡
BEGIN
-- 將程式放在這裡
[EXCEPTION]
-- 將例外處理放在這裡
END;
/

(備註 : -- (用於獨立的一行),或 /* */ )
```

#### 變數類型
```
Varchar2
Number
Date
Boolean
```


#### 游標 (CURSOR)
[Cursor 與 Cursor Variable 的使用](https://zer931.pixnet.net/blog/post/36298232-%5Boracle%5D-cursor-%E8%88%87-cursor-variable-%E7%9A%84%E4%BD%BF%E7%94%A8)

> 類似Java的ResultSet，你可以把Cursor想成是一塊暫存的資料表，裡面存放著SQL的查詢結果，所以透過Cursor我們便可以操作結果的每一列資料，但一次只能處理一列資料。
> 
> 是一種特殊的記憶體結構，可持有SQL敘述句，也能夠記錄程式執行結果。
> 建立在宣告區域, Oracle會再執行前先準備這道敘述句, 讓程式更有效率地使用記憶體。

>為了暫時存放從 cursor 擷取出來的資料列，必須定義一個暫存的變數，而這個變數的型態通常為一列資料(row data)。

```
每個 explicit cursor 都會有以下幾個屬性作為程式控制之用：

%NOTFOUND 
根據從資料集合中擷取的最後一筆資料，來決定回傳 TRUE(有資料) or FALSE(沒資料)。

%FOUND 
與 %NOTFOUND 相反。 

%ROWCOUNT 
回傳資料集合中所包含的資料筆數。當 cursor 從資料集合擷取過資料後，就可以使用此屬性。 

%ISOPEN 
若是 cursor 狀態為 open，則回傳 TRUE；反之則回傳 FALSE。
```

```SQL=
declare

v_prod_name varchar2(80);

begin

select prod_name

into v_prod_name

from products

where rownum =1;

dbms_output.putline(v_prod_name);

end;
```
```
上例為何要在程式中加入rownum = 1?

而上例使用之select陳述式(加入into)的寫法, 我們將其稱為隱式
cursor.

有了隱式cursor, Oracle幾乎可處理任何事,但這是要付出代價的: 程
式執行的速度會變慢, 以此寫法來執行 select 陳述式並非好的寫法,
唯若執行delete、update或是insert時, 你必須使用隱式cursor.
```

- 建立顯式(explicit) cursor是更好的辦法:
```SQL=
declare

v_prod_name varchar2(80);

cursor get_data is

select prod_name

from products

where rownum = 1;

begin

open get_data;

fetch get_data into v_prod_name;

dbms_output.putline(v_prod_name);

close get_data;

end;
```

- CURSOR FOR LOOP
> Cursor FOR loop 是select cursor與FOR loop結合的成果。
> 如果查詢的結果有多筆記錄時，cursor FOR loop 允許你從資料庫中選取更多的記錄。
> 
> 它易於撰寫，並且你不用擔心開啟或關閉cursor的問題; Oracle會在迴圈中處理這個問題。

```SQL=
Declare

l_emp_count number;

i number;

CURSOR get_employee_data is

select count(*)

from employee;

begin

OPEN get_employee_data;

FETCH get_employee_data INTO

l_emp_count;

FOR I in l_emp_count loop

dbms_output.put_line(‘Employee’|| i);

End loop;

CLOSE get_employee_data;

end;
```



###### tags: `SQL`