1. 程式人生 > >Oracle筆記4-pl/sql-分支/循環/遊標/異常/存儲/調用/觸發器

Oracle筆記4-pl/sql-分支/循環/遊標/異常/存儲/調用/觸發器

eal lar 數據交互 實現 after table while gin base

一.pl/sql(Procedure Language/SQL)編程語言
1.概念
PL/SQL是Oracle數據庫對SQL語句的擴展。在普通SQL語句的使用上增加了編程語言的特點,所以PL/SQL把數據操作和查詢語句組織在PL/SQL代碼的過程性單元中,通過邏輯判斷、循環等操作實現復雜的功能或者計算。PL/SQL 只有 Oracle 數據庫有。 MySQL 目前不支持 PL/SQL 的。

2.變量和常量
聲明普通變量:
v_name varchar2(30) := ‘tom‘; (:=為賦值符號;=為比較符號,相當於java中的==);
聲明引用型變量:
v_sal emp.sal%type := 100; 聲明的v_sal變量與emp表中sal字段的類型一致;
聲明記錄型變量:
v_row emp%rowtype; 記錄型變量相當於java中的resultset,用來存儲整張表中的數據;
聲明常量:
v_gender constant number(1) number(1) := 1;

3.分支語句
語法一:if ---then---end if;
語法二:if ---then---else---end if;
語法三:if ---then---elsif---then----else----end if;
舉例:
--年齡小於18,顯示未成年人,18-60,顯示成年人,60以上顯示老年人
declare
v_age number(8) :=#
begin
if v_age < 18 then
dbms_output.put_line(‘未成年人‘);
elsif v_age >= 18 and v_age <= 60 then
dbms_output.put_line(‘成年人‘);
else
dbms_output.put_line(‘老年人‘);
end if;
end;


4.循環語句
語法一:loop---exit when----end loop;
舉例:
--輸出1--100的數
declare
v_num number(8) := 1;
begin
loop
exit when v_num > 100;
dbms_output.put_line(v_num);
v_num := v_num + 1;
end loop;
end;

語法二:while---loop----end loop;
declare
v_num number(8) := 1;
begin
while v_num <= 100 loop
dbms_output.put_line(v_num);
v_num := v_num + 1;
end loop;
end;

語法三:for---in 起始值..終止值---loop---end loop;
declare
v_num number(8) := 1;
begin
for v_num in 1 .. 100 loop
dbms_output.put_line(v_num);
end loop;
end;

5.遊標(cursor)
作用:用來接收多條數據結果,相當於java中的ResultSet
語法:cursor 遊標名稱 is sql 查詢語句;
使用:
open 遊標名稱
loop
fetch 遊標名稱 into 記錄型變理
exit when 遊標名稱%notfound;
邏輯處理
end loop;
close 遊標名稱;
舉例:
--打印emp表的所有信息
DECLARE
CURSOR c_emp IS SELECT * FROM emp;
v_row emp%ROWTYPE;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO v_row;
EXIT WHEN c_emp%NOTFOUND;
dbms_output.put_line(v_row.ename||‘--‘||v_row.job);
END LOOP;
CLOSE c_emp;
END;

--帶參數的遊標
DECLARE
CURSOR c_emp(v_no1 NUMBER, v_no2 NUMBER) IS SELECT * FROM emp WHERE deptno = v_no1 OR deptno = v_no2;
v_row emp%ROWTYPE;
BEGIN
OPEN c_emp(10,20);--傳入部門編號deptno
LOOP
FETCH c_emp INTO v_row;
EXIT WHEN c_emp%NOTFOUND;
dbms_output.put_line(v_row.ename||‘==‘||v_row.job);
END LOOP;
CLOSE c_emp;
END;

6.異常
exception---when----then
--預定義異常
DECLARE
v_num NUMBER(3);
BEGIN
v_num := 10000;
EXCEPTION
WHEN value_error THEN
v_num := 999;
dbms_output.put_line(v_num);
END;

--自定義異常
DECLARE
V_AGE NUMBER(8) := &NUM;
EXC_AGE EXCEPTION; --聲明異常
BEGIN
IF V_AGE > 150 THEN
RAISE EXC_AGE;
END IF;
EXCEPTION
WHEN EXC_AGE THEN
RAISE_APPLICATION_ERROR(-20001, ‘illegal age‘);
END;

二.存儲過程
概念:一段被命名的plsql,預編譯到了數據庫中
語法:
create or replace procedure 存儲過程名字(參數1 [in]/out 數據類型)
as | is
begin

end;
例子1:
--存儲過程,打印指定員工的年薪
create or replace procedure pro_emp_sal(v_no number) is
v_sal number(8, 2);
begin
select sal * 12 + nvl(comm, 0) into v_sal from emp where empno = v_no;
dbms_output.put_line(v_sal);
end;
--方法一調用存儲過程
call pro_emp_sal(7788);
--方法二調用存儲過程
begin
pro_emp_sal(7788);
end;

例子2:帶out參數的存儲過程
CREATE OR REPLACE PROCEDURE pro_emp_sal2(v_no NUMBER, v_yearsal OUT NUMBER) IS
BEGIN
SELECT sal*12 + NVL(comm,0) INTO v_yearsal FROM emp WHERE empno = v_no;
END;
--只能使用方式二調用
DECLARE
v_sal NUMBER(8,2);
BEGIN
pro_emp_sal2(7788,v_sal);
dbms_output.put_line(v_sal);
END;

三.存儲函數
--存儲函數
CREATE OR REPLACE FUNCTION fun_emp_sal(v_no NUMBER)
RETURN NUMBER
IS
v_sal NUMBER(8,2);
BEGIN
SELECT sal*12+NVL(comm,0) INTO v_sal FROM emp WHERE empno = v_no;
RETURN v_sal;
END;
--使用存儲函數
BEGIN
dbms_output.put_line(fun_emp_sal(7788));
END;

註:存儲過程和存儲函數的區別
1、語法不同
2、使用場景:一般存儲函數多被存儲過程使用,存儲過程一般使用在項目和項目之間的數據交互
3、存儲函數可以直接在sql中使用,而存儲過程不能
select ename,sal,func_emp_sal(empno) from emp;


四.使用jdbc調用存儲過程和存儲函數
1.BaseDao用於加載驅動和獲取連接
2.ProcedureDao用於調用存儲過程
3.TestDao用於測試

舉例:
1.BaseDao用於加載驅動和獲取連接
public class BaseDao {
//加載驅動
static{
try {
Class.forName("oracle.jdbc.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

//獲取連接
public static Connection getConn() throws SQLException{
String url="jdbc:oracle:thin:@192.168.92.8:1521:orcl";
String user="qin";
String password="qin";
return DriverManager.getConnection(url, user, password);
}

public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

2.ProcedureDao用於調用存儲過程
public class ProcedureDao {
public static Long getSal(Long v_no){
Connection conn = null;
CallableStatement stmt=null;
Long yearsal=0l;

try {
conn=BaseDao.getConn();
stmt = conn.prepareCall("call pro_emp_sal2(?,?)");//調用存儲過程
stmt.setLong(1, v_no);
stmt.registerOutParameter(2, OracleTypes.NUMBER); //指定參數的數據類型
stmt.execute();
yearsal = stmt.getLong(2);
} catch (SQLException e) {
e.printStackTrace();
}
return yearsal;
}
}

3.TestDao用於測試
public class TestDao {
public static void main(String[] args) {
CursorDao.getEmp(10l);
}
}

五.觸發器
1.--創建添加數據引發操作的觸發器
CREATE OR REPLACE TRIGGER tri_add_emp
AFTER
INSERT ON emp

BEGIN
dbms_output.put_line(‘增加了一條數據‘);
END;

--增加一條數據,看是否會觸發
INSERT INTO emp(empno,ename,deptno) VALUES(1,‘tom‘,10);

2.--系統時間引發的觸發器
CREATE OR REPLACE TRIGGER tri_emp
BEFORE
DELETE OR UPDATE OR INSERT
ON emp
FOR EACH ROW

DECLARE
v_dateStr VARCHAR2(20);
BEGIN
SELECT to_char(SYSDATE,‘yyyy-mm-dd‘) INTO v_dateStr FROM dual;
IF v_dateStr = ‘2017-09-20‘ THEN
raise_application_error(-20002,‘今天系統維護‘);
END IF;
END;

--測試是否能引發觸發器
INSERT INTO emp(empno,ename,deptno) VALUES (3,‘jerry‘,10);

六.誤刪除數據恢復語句
create table tableName_bak
as
select * from tableName as of TIMESTAMP to_timestamp(‘20081126 103435‘,‘yyyymmdd hh24miss‘);

Oracle筆記4-pl/sql-分支/循環/遊標/異常/存儲/調用/觸發器