文章目錄
一、PLSQL簡介
- PLSQL是一種程序語言,叫做過程化SQL語言(Procedural Language/SQL)
- PLSQL是Oracle數據庫對SQL語句的擴展。在普通SQL語句的使用上增加了編程語言的特點。
- PLSQL是Oracle系統的核心語言,現在Oracle的許多部件都是由PLSQL
寫成的 - PLSQL具有簡單、高效、靈活、實用的特點
- Oracle數據庫對SQL 的擴展是PLSQL,SQL Server則是Transac-SQL(T-SQL)
PLSQL的官方文檔地址:https://docs.oracle.com/cd/E11882_01/appdev.112/e25519/toc.htm
二、PLSQL語法結構
1.PLSQL塊
塊(block)是PLSQL的基本程序單位。由聲明部分、執行部分、異常處理部分組成
DECLARE
/*聲明部分----聲明變量、常量、複雜數據類型、遊標等*/
BEGIN
/*執行部分----PLSQL語句和SQL語句*/
EXCEPTION
/*異常處理部分----處理運行錯誤*/
END;----塊結束標記
2.PLSQL塊的分類
匿名塊:動態構造,只能執行一次。
子程序:存儲在數據庫中的存儲過程、函數及包等。當在數據庫上建立好後可以在其它程序中調用它們。
觸發器:當數據庫發生操作時,會觸發一些事件,從而自動執行相應的程序。
示例:(全文代碼環境全部在navicat 查詢界面)
BEGIN
DBMS_OUTPUT.PUT_LINE('hello,word!');--打印語句
END;
三、PLSQL變量
1.命名規則
當編寫PLSQL塊時,爲了臨時存儲數據,需要定義變量和常量,這些名稱的定義需要滿足一下規則:
- 標識名不能超過30個字符
- 第一個字符必須爲字母
- 不分大小寫
- 不能用“-”減號等特殊符號
- 儘量不把變量名聲明和表中字段名一樣
參考規則(name是表名):
標識符 | 命名規則 |
---|---|
程序變量 | v_name |
程序常量 | c_name |
遊標變量 | name_curror |
異常標識 | e_name |
記錄類型 | name_record |
2.變量類型
- 數值類型:NUMBER(p,s)以及子類型INT、FLOAT等
- 字符類型:CHAR(n)、VARCHAR2(n)
- 日期類型:DATE
- 布爾類型:BOOLEAN
3.大小寫規則
當編寫sql語句的PLSQL語句時,既可以採用大寫格式,也可以採用小寫格式。但是爲了程序的可讀性,應儘量按照以下規則:
- SQL關鍵字採用大寫格式,如:SELECT ,UPDATE等
- PLSQL關鍵字採用大寫格式,如:DECLARE, BEGIN, END等
- 數據類型採用大寫格式,如:INT, DATE等
- 標識符采用小寫格式,如:v_sal等
- 數據庫對象和列採用小寫格式,如:emp,sal等
4.註釋
- 單行註釋: --註釋內容
- 多行註釋:/註釋內容/
5.變量賦值
variable:=expression
如果在聲明部分賦值,也可以使用DEFAULT
關鍵字
6.示例
DECLARE
v_name VARCHAR2(10);
v_sal NUMBER(7,2);
v_hiredate DATE;
c_tax_rate CONSTANT NUMBER(3,2):= 0.02;--變量常量賦值,這裏:=也可以用DEFAULT代替
v_tax_sal NUMBER(7,2);
v_valid BOOLEAN DEFAULT TRUE;--DEFAULT也可以用賦值符號:=代替,布爾類型變量主要勇士邏輯判斷
c_empno INT :=7369;
BEGIN
SELECT ename,sal,hiredate INTO v_name,v_sal,v_hiredate FROM emp WHERE EMPNO=c_empno;--將查詢字段結果賦值給變量用INTO關鍵字,前後順序對應
--計算納稅額
v_tax_sal:=v_sal*c_tax_rate;
--打印信息(使用聲明處已被賦值的變量或常量)
DBMS_OUTPUT.PUT_LINE(v_name||'的工資是'||v_sal||',僱傭日期是'||v_hiredate||',納稅額是'||v_tax_sal);
--條件判斷
IF v_valid THEN
DBMS_OUTPUT.PUT_LINE('已覈實');
END IF;
END;
四、PLSQL引用型變量和記錄型變量
當一些變量在聲明的時候就要求和表列具有完全一致的數據類型,因此可以直接使用原表列的類型用於定義變量。
1.引用型變量
是指其數據類型與已經定義的某個數據變量的類型相同,或者與數據庫表的某個列的數據類型相同。如:v_name emp.ename%TYPE
。
DECLARE
v_name emp.ename%TYPE;--v_name的數據類型和emp的ename字段相同
v_sal emp.sal%TYPE;
BEGIN
SELECT ename,sal INTO v_name,v_sal FROM emp WHERE empno=7788;
DBMS_OUTPUT.PUT_LINE(v_name||'的工資是'||v_sal);
END;
2.記錄型變量
變量定義的時候使用%ROWTYPE
操作符,返回一整條記錄的類型,其數據類型和數據庫表的數據結構一致。如:emp_record emp%ROWTYPE
是將emp表的一整條數據類型賦給變量emp_record,emp_record.ename:='ROSE’是取其一個字段ename形成子變量
DECLARE
emp_record emp%ROWTYPE;--emp_record就是emp表的一條記錄類型的集合
c_tax_rate CONSTANT NUMBER(3,2)DEFAULT 0.02;
v_tax_sal NUMBER(7,2);
BEGIN
SELECT * INTO emp_record FROM EMP WHERE EMPNO=7788;
v_tax_sal:=emp_record.sal*c_tax_rate;--emp_record.sal就是取其一個字段的子變量
DBMS_OUTPUT.PUT_LINE(emp_record.ename||'的工資是'||emp_record.sal||',納稅額是'||v_tax_sal);--子變量直接使用emp表的字段名
END;
五、PLSQL運算符
1.關係運算符
運算符 | 含義 |
---|---|
+ | 加號 |
- | 減號 |
* | 乘號 |
** | 乘方 |
DECLARE
v_n1 NUMBER:=3;
v_n2 NUMBER:=5;
BEGIN
DBMS_OUTPUT.PUT_LINE(v_n1+v_n2);
DBMS_OUTPUT.PUT_LINE(v_n1-v_n2);
DBMS_OUTPUT.PUT_LINE(v_n1*v_n2);
DBMS_OUTPUT.PUT_LINE(v_n1/v_n2);
DBMS_OUTPUT.PUT_LINE(v_n1**v_n2);
END;
2.關係運算符
運算符 | 含義 |
---|---|
= | 等於 |
<>,!=,~=,^= | 不等於 |
< | 小於 |
> | 大於 |
< | 小於等於 |
> | 大於等於 |
DECLARE
v_n1 NUMBER(2):=&n1;--&替代變量,系統提示輸入,navicat中無法使用
v_n2 NUMBER(2):=&n2;
BEGIN
IF (v_n1 = v_n2) THEN
DBMS_OUTPUT.PUT_LINE('等於');
ELSIF (v_n1 > v_n2) THEN
DBMS_OUTPUT.PUT_LINE('大於');
ELSIF (v_n1 < v_n2) THEN
DBMS_OUTPUT.PUT_LINE('小於');
END IF;
IF (v_n1 <> v_n2) THEN
DBMS_OUTPUT.PUT_LINE('不等於');
END IF;
END;
3.比較運算符
運算符 | 含義 |
---|---|
IS NULL | 是空值 |
BETWEEN… AND | 介於兩者之間 |
IN | 等於列表中某個值 |
DECLARE
v_num NUMBER :=3;
v_str VARCHAR2(10):='apple';
BEGIN
IF (v_num BETWEEN 0 AND 10) THEN
DBMS_OUTPUT.PUT_LINE('位於0~10');
ELSE
DBMS_OUTPUT.PUT_LINE('不位於0~10');
END IF;
IF (v_num IN (1,3,5)) THEN
DBMS_OUTPUT.PUT_LINE('在集合內');
ELSE
DBMS_OUTPUT.PUT_LINE('不在集合內');
END IF;
IF (v_num IS NULL) THEN
DBMS_OUTPUT.PUT_LINE('爲空');
ELSE
DBMS_OUTPUT.PUT_LINE('不爲空');
END IF;
IF (v_str LIKE 'a%') THEN
DBMS_OUTPUT.PUT_LINE('以a開頭');
ELSE
DBMS_OUTPUT.PUT_LINE('不以a開頭');
END IF;
END;
4.邏輯運算符
運算符 | 含義 |
---|---|
AND | 邏輯與 |
OR | 邏輯或 |
NOT | 取反,如 IS NOT NULL, NOT IN |
DECLARE
v_b1 BOOLEAN :=TRUE;
v_b2 BOOLEAN :=FALSE;
BEGIN
IF (v_b1 AND v_b2) THEN
DBMS_OUTPUT.PUT_LINE('AND--TRUE');
END IF;
IF (v_b1 OR v_b2) THEN
DBMS_OUTPUT.PUT_LINE('OR--TRUE');
END IF;
IF (NOT v_b2) THEN
DBMS_OUTPUT.PUT_LINE('n_b2--NOT--TRUE');
END IF;
END;
5.NULL的運算特點
- 空值加數字仍是空值:NULL+<數字>=NULL,所以如果要避免空值話,可以使用NVL函數
- 空值連接字符,結束是字符:NULL||<字符串>=<字符串>
DECLARE
v_num NUMBER :=3;
v_str VARCHAR2(10):='apple';
BEGIN
DBMS_OUTPUT.PUT_LINE(v_num+NULL);
DBMS_OUTPUT.PUT_LINE(v_str||NULL);
END;
六、條件控制語句
1.IF 語句
- 簡單條件判斷:IF-THEN
語法格式:
IF condition THEN
statements;
END IF;
示例:
--輸入員工號,判斷員工工資顯示小於3000的員工
DECLARE
v_name EMP.ENAME%TYPE;
v_sal EMP.SAL%TYPE;
BEGIN
SELECT ename,sal INTO v_name,v_sal FROM EMP WHERE EMPNO=&n;
IF v_sal<3000 THEN
DBMS_OUTPUT.PUT_LINE(v_name);
END IF;
END;
- 二重條件分支:IF-THEN-ELSE
語法格式:
IF condition THEN
statements;
ELSE
statements;
END IF;
示例:
--輸入員工號,判斷員工工資,將工資小於3000的員工工資漲200,並顯示漲工資的員工姓名,其它員工顯示員工姓名及工資
DECLARE
v_name EMPNEW.ENAME%TYPE;
v_sal EMPNEW.SAL%TYPE;
v_empno EMPNEW.EMPNO%TYPE=7788;
BEGIN
SELECT ename,sal INTO v_name,v_sal FROM EMPNEW WHERE EMPNO=v_empno;
IF v_sal<3000 THEN
UPDATE EMPNEW SET SAL=SAL+200 WHERE EMPNO=&v_empno;
COMMIT;--數據庫操作語言DML,執行後需要提交
DBMS_OUTPUT.PUT_LINE(v_name||'漲工資了');
ELSE
DBMS_OUTPUT.PUT_LINE(v_name||'的工資是'||v_sal);
END IF;
END;
- 多重條件分支:IF-THEN-ELSIF
語法格式:
IF condition THEN
statements;
ELSIF condition THEN
statements;
ELSE
statements;
END IF;
示例:
--輸入員工號,判斷員工工資,工資小於2000,顯示低收入,工資小於6000,顯示中等收入,其它顯示高收入
DECLARE
v_name EMPNEW.ENAME%TYPE;
v_sal EMPNEW.SAL%TYPE;
v_empno EMPNEW.EMPNO%TYPE:=7788;
BEGIN
SELECT ename,sal INTO v_name,v_sal FROM EMPNEW WHERE EMPNO=v_empno;
IF v_sal<2000 THEN
DBMS_OUTPUT.PUT_LINE(v_name||'低收入');
ELSIF v_sal<6000 THEN
DBMS_OUTPUT.PUT_LINE(v_name||'中等收入');
ELSE
DBMS_OUTPUT.PUT_LINE(v_name||'其它');
END IF;
END;
2.CASE
使用CASE語句執行多重條件分支操作,語句更加簡潔執行效率更好。
- 單一選擇符進行等值比較
語法格式:
CASE selector
WHEN expression1 THEN sequence_of_statements1;
WHEN expression2 THEN sequence_of_statements2;
...
WHEN expressionN THEN sequence_of_statementsN;
[ELSE sequence_of_statements;]
END CASE;
示例:
--輸入成績等級,判斷屬於哪個層次,並打印輸出
DECLARE
v_grade CHAR(1):='&n';
BEGIN
CASE v_grade
WHEN 'A' THEN
DBMS_OUTPUT.PUT_LINE('優秀');
WHEN 'B' THEN
DBMS_OUTPUT.PUT_LINE('中等');
ELSE
DBMS_OUTPUT.PUT_LINE('其它');
END CASE;
END;
- 多種條件進行非等值比較
語法格式:
CASE
WHEN condition1 THEN sequence_of_statements1;
WHEN condition2 THEN sequence_of_statements2;
...
WHEN conditionN THEN sequence_of_statementsN;
[ELSE sequence_of_statements;]
END CASE;
示例:
--輸入員工號,獲取員工工資,判斷工資,如果小於1500,補助加100,如果小於2500,補助加80,如果小於5000,補助加50
DECLARE
v_name EMPNEW.ENAME%TYPE;
v_sal EMPNEW.SAL%TYPE;
v_empno EMPNEW.EMPNO%TYPE:=7788;
BEGIN
SELECT ename,sal INTO v_name,v_sal FROM EMPNEW WHERE EMPNO=v_empno;
CASE
WHEN v_sal<1500 THEN
UPDATE EMPNEW SET COMM=NVL(COMM,0)+100 WHERE EMPNO=v_empno;
WHEN v_sal<2500 THEN
UPDATE EMPNEW SET COMM=NVL(COMM,0)+80 WHERE EMPNO=v_empno;
WHEN v_sal<5000 THEN
UPDATE EMPNEW SET COMM=NVL(COMM,0)+50 WHERE EMPNO=v_empno;
COMMIT;
END CASE;
END;
七、循環語句
1.基本循環
語法格式:
LOOP
statement1;
......
END LOOP;
示例:
--循環打印數字1~10
DECLARE
v_n INT:=1;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE(v_n);
v_n:=v_n+1;--變量自增
EXIT WHEN v_n>10;--退出條件
END LOOP;
END;
2.WHILE循環
語法格式:
WHILE condition LOOP
statement1;
......
END LOOP;
示例:
DECLARE
v_n INT:=1;
BEGIN
WHILE v_n <=10 LOOP
DBMS_OUTPUT.PUT_LINE(v_n);
v_n:=v_n+1;
END LOOP;
END;
3.FOR循環
語法格式:
FOR counter in [REVERSE] lower_bound ...upper_bound LOOP
statement1;
......
END LOOP;
注意:步長默認爲1,且不需要事先定義變量,REVERSE反相打印
示例:
BEGIN
FOR i in 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(i);
END LOOP;
END;
BEGIN
FOR i IN REVERSE 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(i);
END LOOP;
END;
八、嵌套循環和退出語句
1.嵌套循環
嵌套循環是指在一個循環語句中嵌入兩一個循環語句,標號用於標記嵌套塊或嵌套玄幻,使用<<label_name>>定義標號
DECLARE
v_result INT;
BEGIN
<<outter>>
FOR i IN 1..5 LOOP
<<inter>>
FOR j IN 1..4 LOOP
v_result:=i;
EXIT outter WHEN i=3;
DBMS_OUTPUT.PUT_LINE(i||j);
END LOOP;
DBMS_OUTPUT.PUT_LINE('內:'||v_result);--整個內循環結束一次記錄一次i的值
END LOOP;
DBMS_OUTPUT.PUT_LINE('外:'||v_result);--當整個外循環全部結束後纔會執行,此時就是結束外循環時j的值
END;
2.退出語句
- EXIT和EXIT WHEN語句
- EXIT語句用於直接退出當前循環
- EXIT WHEN語句用於在滿足特定條件時退出當前循環
DECLARE
v_cnt INT:=1;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE(v_cnt);
EXIT WHEN v_cnt=10;
v_cnt:=v_cnt+1;
END LOOP;
END;
- CONTINUE和CONTINUE WHEN語句
- CONTINUE語句用於直接結束當前循環並繼續下一組循環
- CONTINUE WHEN語句用於在滿足特定條件時結束當前循環並繼續下一組循環
DECLARE
v_cnt INT:=0;
BEGIN
LOOP
v_cnt:=v_cnt+1;
CONTINUE WHEN v_cnt=5;
DBMS_OUTPUT.PUT_LINE(v_cnt);
EXIT WHEN v_cnt=10;
END LOOP;
END;
九、順序語句
1.GOTO語句
GOTO語句用於跳轉到特定標號處執行語句
GOTO label_name;
注意當桑勇GOTO跳轉到特定標號時,標號後面至少要包含一條執行語句
比較繁瑣,減少使用
DECLARE
v_cnt INT:=1;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE(v_cnt);
IF v_cnt=10 THEN
--EXIT;
GOTO end_loop;
END IF;
v_cnt:=v_cnt+1;
END LOOP;
<<end_loop>>
DBMS_OUTPUT.PUT_LINE('循環結束');--標號後面至少一條語句
END;
2.NULL語句
NULL語句不會執行任何操作,並且會直接將控制傳遞到下一個語句,使用該語句的主要目的是提高PLSQL的可讀性
--根據輸入的員工號,判斷員工的工資,如果工資小於3000,將該員工的不止加工資的2%,並打印輸出某員工的獎金更新了
DECLARE
v_name EMPNEW.ENAME%TYPE;
v_sal EMPNEW.SAL%TYPE;
v_empno EMPNEW.EMPNO%TYPE:=7369;
BEGIN
SELECT ename,sal INTO v_name,v_sal from EMPNEW WHERE empno=v_empno;
IF v_sal<3000 THEN
UPDATE EMPNEW set COMM=nvl(comm,0)+sal*0.2 WHERE ename=v_name;
COMMIT;
DBMS_OUTPUT.PUT_LINE(v_name||'的獎金更新了');
ELSE
NULL;--沒有任何操作
END IF;
END;