PLSQL是Oracle內部的一種編程語言。
PLSQL是一門語言。叫作過程化SQL語言(Procedural Language SQL)
PLSQL是一種過程化語言,屬於第三代語言,它與C、C++、Java等語言同樣關注於處理細節,能夠用來實現比較複雜的業務邏輯。
PL/SQL是對結構化查詢語言(SQL)的過程語言擴展。java
PL/SQL的基本單位叫作一個區段,由三個部分組成:一個聲明部分,一個可運行部分,和排除-構建部分。
PL/SQL區段只被編譯一次而且以可運行的形式儲存,以下降響應時間。web
實際工做中,PLSQL多用於寫觸發器、存儲過程、函數等。sql
PL/SQL的基本單位叫作一個區段,由三個部分組成:一個聲明部分,一個可運行部分,和排除-構建部分。
這裏聲明只有運行部分是必須的,其他均是可選,以下:數據庫
declare --(可選,聲明變量用)
begin --(must) null;
exception --(可選)
end; --(must)
以下咱們建立一個最簡單的PLSQL語句塊編程
begin null;
end;
/
在命令行執行,結果以下:
數組
須要指出的是,這裏的 null 不能夠省略,PLSQL語句塊中必須包含一條語句。bash
下面咱們寫一個最簡單而且打印Hello World的PLSQL。編程語言
set serveroutput on; --用於打開控制檯輸出服務,默認是off,則不打印
begin dbms_output.put_line('HelloWorld'); --相似於java的System.out.print
end;
/
在命令行執行,結果:
svg
declare用於聲明變量。
變量名稱與變量類型不可省略,默認值經過 :=
賦值,默認值能夠省略。
格式以下:函數
declare
v_variable1 variable_type [ := default_value];
v_variable2 variable_type [ := default_value];
變量聲明
規則:
v_
開頭;PLSQL的基本變量類型有7個。以下:
根據以上類型,咱們寫一個含有變量聲明的PLSQL。
declare
v_temp number(1);
v_count binary_integer := 0;
v_sal number(7,2) :=4000.00;
v_date date := sysdate;
v_pi constant number(3,2) := 3.14; --相似於Java的final關鍵字,表示常量
v_valid boolean := false;
v_name varchar2(20) not null := 'MyName';
begin
dbms_output.put_line('v_temp value: '||v_temp);
dbms_output.put_line('v_count value: '||v_count);
dbms_output.put_line('v_sal value: '||v_sal);
dbms_output.put_line('v_date value: '||v_date);
dbms_output.put_line('v_pi value: '||v_pi);
-- dbms_output.put_line('v_valid value: '||v_valid); --不能打印boolean值
dbms_output.put_line('v_name value: '||v_name);
end;
命令行結果以下:
這裏須要指出的是,PLSQL的dbms_output.put_line()
函數不能直接打印boolean類型。
在工做中,變量的做用更多的是存儲某個字段中的值,於是保證變量數據類型與字段數據類型一致是頗有必要的。
PLSQL中,在變量聲明時,能夠經過%type
得到指定字段(變量)的數據類型。這種方式能夠確保當源表的字段類型改變時,變量的類型自動改變。
以下:
declare
v_empno number(4);
v_empno2 emp.empno%type; --v_empno2的類型是表emp的empno字段的類型
v_empno3 v_empno2%type; --v_empno3的類型是變量v_empno2的類型
PLSQL提供了兩種複合變量。
以下聲明一個Table變量
declare
type type_table_emp_empno is table of emp.empno%type index by binary_integer; --聲明一個數組類型
v_empnos type_table_emp_empno; --利用類型聲明變量
begin
v_empno(0) := 7369;
v_empno(2) := 7839;
v_empno(-1) := 9999; --Table類型的下標能夠是負數
dbms_output.put_line(v_empno(-1));
end;
聲明一個Record類型
--RECORD類型
declare
type type_record_dept is record
(
deptno dept.deptno%type,
dname dept.dname%type,
loc dept.loc%type
);
v_temp type_record_dept;
begin
v_temp.deptno := 50;
v_temp.dname := 'aaa';
v_temp.loc := 'bj';
dbms_output.put_line(v_temp.deptno||v_temp.dname||v_temp.loc);
end;
這裏若是表的結構發生了變化,咱們如何保證聲明的複合變量和表中的變量相同呢,能夠經過rowtype實現。
%rowtype:定義一個表示表中一行記錄的變量
以下:
declare
v_temp dept%rowtype;
begin
v_temp.deptno := 50;
v_temp.dname := 'aaa';
v_temp.loc := 'bj';
dbms_output.put_line(v_temp.deptno||v_temp.dname||v_temp.loc); end;
這裏關於 %type
和 %rowtype
作一個簡單的對比說明:
以下:
%TYPE
爲了使一個變量的數據類型與另外一個已經定義了的變量(尤爲是表的某一列)的數據類型相一致,當被參照的那個變量的數據類型改變了以後,這個新定義的變量的數據類型會自動跟隨其改變,無需修改PL/SQL程序。當不能確切地知道被參照的那個變量的數據類型時,就只能採用這種方法定義變量的數據類型。
%ROWTYPE
若是一個表有較多的列,使用%ROWTYPE來定義一個表示表中一行記錄的變量,比分別使用%TYPE來定義表示表中各個列的變量要簡潔得多,而且不容易遺漏、出錯。這樣會增長程序的可維護性。當表的某些列的數據類型改變了以後,這個新定義的變量的數據類型會自動跟隨其改變,無需修改PL/SQL程序。當不能確切地知道被參照的那個表的結構及其數據類型時,就只能採用這種方法定義變量的數據類型。
異常塊經過exception關鍵字聲明,以下:
declare
v_num number := 0;
begin
v_num := 2/v_num;
dbms_output.put_line(v_num);
exception
when others then
dbms_output.put_line('error');
end;
/
PLSQL中能夠寫SQL語句,和平時的SQL語法基本一致,須要注意的是如下幾點:
這裏須要解釋的是,select語句不返回值則無心義,返回許多則變量裝不了。
下面咱們有一張測試表,而且根據這張表,實驗理解PLSQL的SQL語句。
set serveroutput on; --該服務開啓一次便可,若是以前開啓過無需再次開啓。
declare
v_dep ljb_test.dep%type; --type
v_name ljb_test.name%type; --type
v_test ljb_test%rowtype; --rowtype
--測試insert&update的數據
v_new_dep ljb_test.dep%type := 10;
v_new_name ljb_test.name%type := '小明';
v_new_salary ljb_test.salary%type := 5000;
v_anoter_name ljb_test.name%type := '大明';
begin --select語句必須返回一條記錄,而且只能返回一條記錄 select dep, name into v_dep, v_name from ljb_test where salary = 6000; --限定條件必定要保證返回一條記錄
dbms_output.put_line(v_dep||v_name);
select * into v_test from ljb_test where salary = 6000; --限定條件必定要保證返回一條記錄
dbms_output.put_line(v_test.dep||v_test.name||v_test.salary);
--insert,與普通SQL語句一致,只是能夠插入變量
insert into ljb_test values(v_new_dep, v_new_name, v_new_salary);
commit; --執行完插入語句記得提交事務
--update,與普通SQL語句一致,只是能夠插入變量
update ljb_test t set name = v_anoter_name where t.name = v_new_name;
--delete,與普通SQL語句一致,只是能夠插入變量
delete from ljb_test t where t.dep = '1'; --刪除部門1的記錄
end;
/
輸出結果:
同時咱們看下更新後的測試表:
能夠看到數據已經更新。
DDL語句不能直接執行,必須使用 execute immediate ''
進行包裹;
以下,咱們經過PLSQL建立一張表:
begin execute immediate 'create table tb(aaa varchar2(255) default ''asd'')'; --兩個單引號表明一個單引號
end;
/
須要指出的兩點:
execute immediate ''
包裹,不然報錯ORA-06550;咱們在命令行執行,並查看該表
一樣的,truncate和drop寫法以下:
begin execute immediate 'truncate table tb'; --刪除記錄,釋放表空間
execute immediate 'drop table tb'; --刪除記錄及定義,釋放表空間 end; /
可是有個例外:就是delete。
delete既可使用execute也能夠不使用,以下兩種寫法均是正確的。
begin execute immediate'delete tb'; --delete刪除記錄,但不釋放表空間
commit;
delete tb;
commit;
end;
/
這裏能夠這樣理解,實際上delete table_name
等價於 delete from table_name
,是一種DML語言,於是能夠直接執行。
這裏針對drop、truncate、delete在複習下三者的區別
判斷循環語句是PLSQL的重要語句。
判斷語句也叫作分支語句,經過if實現。以下經過一個簡單實例進行理解:
對於以下表:
咱們寫一個薪水等級判斷語句:
<3000 low
3000~5000 middle
其他 high
--if語句
declare
v_sal ljb_test.salary%type;
begin
select salary into v_sal from ljb_test where name = 'ri';
if(v_sal < 3000) then
dbms_output.put_line('low');
elsif(v_sal < 5000) then --elsif
dbms_output.put_line('middle');
else --else後面沒有then
dbms_output.put_line('high');
end if;
end;
/
set serveroutput on; --也能夠放在下面,可是須要在以前增長一個 /
/
和Java等語句的if語句極其類似,不一樣的是具體的語法,須要注意其特色。
輸出結果以下:
與Java中的循環語句相似,PLSQL也要擁有相似的三種循環語句。爲了方便理解,我使用Java循環的區分方式來區分PLSQL的三種循環。
即:
do while循環
while循環
for循環
對於三種循環,均具備如下特色:
PLSQL的循環必定是以loop開頭,以end loop結束。
先打印,而後在判斷條件,以下:
--相似於do while 循環
set serveroutput on;
declare
i binary_integer := 1; --聲明一個計數變量
begin
loop --循環老是loop開頭
dbms_output.put_line(i);
i := i + 1;
exit when(i>=11); --循環退出語句
end loop; --循環老是end loop結束
end;
/
命令行打印結果以下:
先判斷,在循環打印
--while循環
declare
j binary_integer := 1; --聲明一個計數變量
begin
while j<11 loop --循環退出語句,循環老是loop開頭
dbms_output.put_line(j);
j := j+1;
end loop; --循環老是end loop結束
end;
/
結果以下:
for循環無需declare塊聲明變量。
1..10表示1-10,注意是兩個點。
--for循環
begin --for循環無需declare聲明變量
for k in 1..10 loop --1..10表示1-10,注意是兩個點
dbms_output.put_line(k);
end loop;
for k in reverse 1..10 loop --reverse表示逆序
dbms_output.put_line(k);
end loop;
end;
/
結果以下:
前面說過,PLSQL是一門過程語言,因此也支持相似於Java的異常處理機制。
須要指出的是,PLSQL的異常處理實際工做中並不經常使用,緣由很簡單,爲了提升程序的可移植性(用於多個數據庫),咱們通常把異常處理放在Java等語言中處理。
異常處理的核心應用通常是日誌表。
因此,下文咱們僅做簡單的介紹。
首先,明確一點,異常處理只能捕獲運行時的異常,編譯時的異常沒法捕獲,於是若是存在編譯異常,則程序沒法運行,更沒法調用異常處理機制。
begin insert into dual values('',''); --插入字段數明顯不符合
exception
when others then
dbms_output.put_line('ERROR!');
end;
/
這時,程序沒法編譯經過,會直接報錯:
下面,咱們就以前PLSQL中select語句返回一條記錄的要求,來寫幾個簡單的異常捕獲程序:
set serveroutput on;
declare
v_name ljb_test.name%type;
begin
select name into v_name from ljb_test;
exception
when too_many_rows then --too_many_rows,返回值超過一條
dbms_output.put_line('返回值太多');
when others then
dbms_output.put_line('error');
end;
/
運行程序,結果以下:
declare
v_name ljb_test.name%type;
begin
select name into v_name from ljb_test where 1 = 0;
exception
when no_data_found then --no_data_found,無數據異常
dbms_output.put_line('無數據');
when others then
dbms_output.put_line('error');
end;
/
結果以下:
異常處理最核心的應用應該就是日誌表,而日誌表多用於存儲過程等。
create table err_log( err_id number primary key, err_code number, err_msg varchar2(1024), err_date date );
create sequence seq_err_log start with 1 increment by 1;
declare
v_errcode number;
v_errmsg varchar2(1024);
v_name ljb_test.name%type;
begin --insert into dual values('0','2'); --編譯時錯誤是沒法經過異常捕獲處理的
select name into v_name from ljb_test;
--commit;
exception
when others then
rollback; --回滾,取消錯誤操做的影響
v_errcode := SQLCODE; --SQLCODE,關鍵字,表明出錯代碼,Oracle的錯誤代碼所有是負數
v_errmsg := SQLERRM; --SQLERRM,關鍵字,表明出錯信息
insert into err_log values(seq_err_log.nextval,v_errcode,v_errmsg,sysdate);
commit; --不要忘記commit
end;
/
咱們查詢下對應的日誌表內容:
若是是存儲過程當中的日誌表,能夠添加一個pro_name字段。
插入的時候,直接插入該存儲過程的名字便可。
至此,PLSQL的基本語法已經學習完成,有關存儲過程、遊標等的介紹,將會另起一文,本文僅對基本語法等作簡單學習總結。