oracle-third
1.PL/SQL編程語言
1)什麼是PL/SQL:
PL/SQL==(procedure language/SQL)
PL/SQL是oracle對sql語言的過程化擴展,在sql命令語言中增加了過程處理語句(如分支,循環),使SQL語句具有過程處理能力。
例子1:給所有人的工資漲10%。
update emp set sal=sal*1.1;
例子2:按職工職位漲工資總裁漲1000元,經理漲800元,其他人員漲400元。
使用jdbc打開連接,創建statement,執行三次executeUpdate(sql)
本例子我們不能使用一條sql來完成這個操作,我們可以分解成多個sql來完成,也可以使用我們的PL/SQL做,那麼PL/SQL實際上相當於我們的jdbc的感覺,但是呢相比於jdbc來說jdbc是外部程序,跟我們在界面手工執行sql差不多,但是PL/SQL不同他是在oracle服務器裏執行的程序。效率當然不一樣了。
set serveroutput on;//打開控制檯輸出
2)PL/SQL的語法結構:
declare
--說明部分 (變量申明,光標申明,例外說明)
begin
--語句序列:DML語句多個
exception
--例外異常處理語句
end;
/
3)常量和變量的定義 :
※聲明變量(char ,varchar2,date,number,boolean,long)
var1 char(30); --說明變量名,類型等等信息以分號結尾。
var2 boolean:=true; --說明變量並且指定默認值
username emp.ename%type; --引用行變量和emp表中ename類型一樣
emp_rec emp%rowtype; --記錄類型的變量
※使用變量
empname:=’sdf'
我們在程序中定義了變量之後使用sql語句給我們變量賦值的關鍵字是
into
declare
emprec emp%rowtype;
begin
select * into emprec from emp where empno=7876;
dbms_output.put_line(emprec.ename ||’工資爲’||emprec.sal);
end;
4)IF判斷
※語法:
IF 條件 THEN 語句1; 語句2; ... END IF; |
IF 條件 ELSE 語句序列; END IF; |
IF 條件 THEN語句序列; ELSIF 條件 THEN語句序列; ... ELSE 語句序列; END IF; |
例子1:從控制檯輸入姓名,然後輸出‘我是xxx’
declare
myname_ varchar2(20) :='&myname_p';
begin
dbms_output.put_line('我是'||myname_);
end;
例子2:從控制檯輸入姓名,判斷是不是李嘉誠如果是李嘉誠輸出:‘我是李嘉誠,我有錢我任性。’,如果不是那麼輸出‘我不是李嘉誠,我是xxx’;
declare
myname_ varchar(20):='&myname_p';
begin
if myname_='李嘉誠' then
dbms_output.put_line('我是李嘉誠,我有錢,我任性。');
else
dbms_output.put_line('我不是李嘉誠,我是'||myname_||'(⊙o⊙)!!!');
end if;
end;
declare
myname_ varchar2(20):='&inputname';
begin
if myname_='李嘉誠' then
dbms_output.put_line('我是李嘉誠,我有錢我任性。');
elsif myname_='馬雲' then
dbms_output.put_line('我是馬雲,我有錢我任性。');
else
dbms_output.put_line('矮窮矬');
end if;
end;
高難度例子3:從控制檯輸入用戶的編號,判斷員工工資是否大於5000如果大於5000輸出厲害了我的哥;
分析:1.得到用戶編號用地址符的方式接受輸入,你需要一個變量來接收
2.還的拿到員工工資,sql into ,你又需要一個變量來接收
3.這時候你就可以開始if判斷 然後輸出
declare
empno_ number :=&empno;
emprec_ emp%rowtype;
usercount_ number;
begin
select count(1) into usercount_ from emp where empno=empno_;
If usercount_=1 then
select * into emprec_ from emp where empno=empno_;
if emprec_.sal>5000 then
dbms_output.put_line('厲害了我的哥,您的工資是:'||emprec_.sal||'元');
else
dbms_output.put_line('夥計你還的加油啊!');
end if;
else
dbms_output.put_line('編號爲:的員工找到了0或者找到了多條');
end if;
end;
5)循環
語法1: while 條件 loop 語句1; 語句2; ... total :=total+1; end loop; |
語法2: loop exit when 條件; 語句1; 語句2; ... end loop; |
語法3: for i in 1..4 loop 語句1; 語句2; end loop; |
列子1:語法1從1輸出到100?
declare
index_ number :=1;
begin
while index_<=100 loop
dbms_output.put_line(index_);
index_:=index_+1;
end loop;
end;
列子2:語法2從1輸出到100?
declare
index_ number:=1;
begin
loop exit when index_>=100;
dbms_output.put_line(index_);
index_:=index_+1;
end loop;
end;
列子3:語法3從1輸出到100?
declare
index_ number :=1;
begin
for index_ in 1..100
loop
dbms_output.put_line(index_);
end loop;
end;
6)遊標
當在PL/SQL中查詢出來的結果集是多個的時候,我們要分別對每個記錄進行處理那麼我們要用到遊標,PL/SQL中的遊標我們可以想象成jdbc中的ResultSet的next next的這個過程。
語法: cursor 遊標名(參數1類型,參數2類型...) is select語句
用法:
→打開遊標: open 遊標名
→取出一行遊標的值: fetch 遊標名into變量
→關閉遊標: close 遊標名
→遊標的結束方式: exit when 遊標名%notfound
例子1:使用遊標的方式輸出所有員工的姓名和編號?
declare
cursor empcur is select * from emp;
emprec emp%rowtype;
begin
open empcur;
loop
fetch empcur into emprec;
exit when empcur%notfound;
dbms_output.put_line(emprec.ename||'工號'||emprec.empno);
end loop;
close empcur;
end;
SAL EMPNO ENAME
-------- ---------- ---------
2000 1 王振
2450 7782 CLARK
5000 7839 KING
1300 7934 MILLER
SAL EMPNO ENAME
------- ---------- ----------
3000 1 王振
3675 7782 CLARK
7500 7839 KING
1950 7934 MILLER
例子2:爲部門號爲10的員工漲工資?
declare
cursor empcur is select * from emp;
emprec emp%rowtype;
begin
open empcur;
loop
fetch empcur into emprec;
exit when empcur%notfound;
if emprec.deptno=10 then
dbms_output.put_line(emprec.ename||'工號'||emprec.empno);
update emp t set t.sal=t.sal+1000;
end if;
end loop;
close empcur;
end;
例子3:給10號部門漲10%,給20號部門漲20%,給30號部門漲30%,姓名是《MARTIN
》這個員工不能漲。
declare
cursor empcur is select * from emp;
emprec emp%rowtype;
begin
open empcur;
loop
fetch empcur into emprec;
exit when empcur%notfound;
if emprec.ename!='MARTIN' then
if emprec.deptno=10 then
update emp set sal=sal*1.1 where empno=emprec.empno;
elsif emprec.deptno=20 then
update emp set sal=sal*1.2 where empno=emprec.empno;
elsif emprec.deptno=30 then
update emp set sal=sal*1.3 where empno=emprec.empno;
end if;
end if;
end loop;
close empcur;
end;
7)例外(異常)
異常是程序設計中提供的一種功能,用來增強程序的容錯性和健壯性。
例外類型 |
描述 |
no_data_found |
沒有找到數據 |
too_many_rows |
Select into from 匹配了多個行 |
zero_divide |
被零除 |
value_error |
算術或者轉換錯誤 |
timeout_on_resource |
在等待資源時發生意外 |
我們可以拋出自定義的例外,必須在聲明部分聲明意外?
例子1:捕獲plsql的意外?
declare
ename_ emp.ename%type;
begin
select ename into ename_ from emp where empno=0;
exception
when no_data_found then
dbms_output.put_line('找不到員工');
end;
例子2:拋出一個自定義異常
declare
empcount_ number;
empno_ number:=&empno_p;
user_not_found exception;
begin
select count(1) into empcount_ from emp where empno=empno_;
if empcount_<=0 then
raise user_not_found;
end if;
exception
when user_not_found then
dbms_output.put_line('用戶未找到');
end;
8)存儲過程
存儲過程(stored procedure)是在大型數據庫系統中,一組爲了完成特定功能的SQL語句,經過編譯後存儲在數據庫中,用戶通過指定存儲過程的名字並給出參數來執行它。存儲過程對象是數據庫中的一個重要對象,大型的企業級應用,會使用存儲過程來完成一系列複雜的操作。主要的作用是能被外部程序調用,比如jdbc;
語法:
create or replace procedure 過程名(參數1參數類型,參數2 參數類型,......) is
申明變量
begin
pl/sql語句
end;(或者end存儲過程名)
例子1:我們要給指定員工漲工資100元,並且打印出漲前工資和漲工資後的工資?
create or replace procedure addsal(empno_p number) is
emprec_ emp%rowtype;
empsalnew number;
begin
select * into emprec_ from emp where empno=empno_p;
empsalnew:=emprec_.sal+1000;
update emp set sal=empsalnew where empno=empno_p;
dbms_output.put_line('員工'||emprec_.ename||'原工資:'||emprec_.sal||'元,漲後工資:'||empsalnew);
exception
when no_data_found then
dbms_output.put_line('找不到員工');
end;
調用存儲過程
begin
addsal(7876);
commit;
end;
9)函數
函數和存儲過程的十分類似,區別在於函數是有返回值的,而過程沒有返回值,當然我們可以使用存儲過程的out參數來完成數據的返回動作。
函數的語法:
create or replace function 函數名(參數1 in參數類型,參數2 out參數類型...) return數據類型is
申明變量(包含結果變量);
begin
return 結果變量;
end 函數名;
例子1:用函數來獲取指定員工的年收入?
create or replace function queryEmpYearSal(empno_p in number) return number is
empsal_return number;
emprec_ emp%rowtype;
begin
select * into emprec_ from emp where empno=empno_p;
empsal_return:=emprec_.sal*12 + nvl(emprec_.comm,0);
return empsal_return;
exception
when no_data_found then
dbms_output.put_line('找不到員工信息');
empsal_return:=-1;
return empsal_return ;
end;
//sql中直接調用
select queryEmpYearSal(7876) from dual;
例子2:編寫一個函數完成nvl的功能?
create or replace function nvlnew(num1 number,num2 number) return number is
return_num number;
begin
if num1 is null then
return_num:=num2;
else
return_num:=num1;
end if;
return return_num;
end nvlnew;
10)觸發器
觸發器是一個與表關聯的PL/SQL存儲程序,每當一個特定的數據操作語句發生時例如:
insert,update,delete在指定的表上發生前或者發生後,oracle會自動執行觸發器中定義的語句序列。
1)觸發器的作用
數據確認:員工的工資超過10000000將員工的職位設置BIGBOSS。
實施複雜的安全性校驗:男人的工資不能超過200
做審計、備份等操作。
2)觸發器的分類
語句級觸發
行級觸發
3)觸發器的語法
create or replace trigger 觸發器名 before或者after
delete、insert、update [of列名]
on 表名
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[for each row[when 條件]]---使用old和new關鍵字來引用變化前後
declare
申明變量等;...
begin
PL/SQL語句序列;
end 觸發器名;
注意:觸發器拋出運行時異常時可以阻斷事務提交;raise_application_error(-9999,’錯誤消息’)
準備活動:
create table teacher_info(
id varchar2(50) primary key,
tname varchar2(20) not null,
sex varchar2(2) check(sex in('男','女')),
stu_count number(10)
);
create table student_info(
id varchar2(50) primary key,
stuname varchar2(20) not null,
owner_tech_id references teacher_info(id)
);
insert into teacher_info values('1','喬布斯','男',49);
insert into teacher_info values('2','川普','男',49);
insert into student_info values('1','李雷','1');
insert into student_info values('2','韓梅梅','1');
insert into student_info values('3','tom','1');
insert into student_info values('4','jerry','1');
例子1:老師和學生一對多,當插入學生前判斷老師的學生數量不能超過50人;
create or replace trigger triger_before_insert_stu
before insert on student_info
-- referencing NEW as new
for each row
declare
stucount_ number;
begin
select stu_count into stucount_ from teacher_info where id=:NEW.owner_tech_id;
if stucount_>=50 then
raise_application_error(-20001,'老師的學生不能超過50人');
end if;
end triger_before_insert_stu;
例子2:當刪除學生的後,修改老師的學生數量字段;
create or replace trigger trigger_delete_stu after delete
on student_info
for each row
declare
begin
update teacher_info set stu_count=stu_count-1 where id=:OLD.owner_tech_id;
end trigger_delete_stu;
例子3:當插入學生後,修改老師學生數量字段;
create or replace trigger trigger_after_insert_stu after insert
on student_info
for each row
declare
begin
update teacher_info set stu_count=stu_count+1 where id=:NEW.owner_tech_id;
end trigger_after_insert_stu;
例子4:當修改學生所屬老師時候,修改老師的學生數量字段;
create or replace trigger triger_alter_update_stu
after update on student_info
-- referencing NEW as new
for each row
declare
stucount_ number;
begin
update teacher_info set stu_count=stu_count-1 where id=:OLD.owner_tech_id;
update teacher_info set stu_count=stu_count+1 where id=:NEW.owner_tech_id;
end triger_before_insert_stu;
2.JAVA調用存儲過程
存儲過程1:
create or replace procedure test_procedure(empno_p number, out_sal_ out number) is
emprec_ emp%rowtype;
begin
select * into emprec_ from emp where empno=empno_p;
out_sal_:=emprec_.sal;
exception
when no_data_found then
dbms_output.put_line('找不到員工');
out_sal_:=-1;
end;
存儲過程2:
create or replace procedure test_procedure_cursor(deptno_p number,outemplist outsys_refcursor) is
begin
open outemplist for select * from emp where deptno=deptno_p;
end;