PL/SQL程序基礎1
一.實驗目標
掌握PL/SQL程序的基本結構編程,具備如下能力:
1、針對數據庫應用領域的數據需求,設計出基於Oracle數據庫的解決方案的能力;
2、承擔Oracle數據庫系統的實施、運行與維護等基本工作的能力。
二.實驗項目
編寫存儲過程或存儲函數完成以下各題,存儲過程或函數依次命名爲obj2_1、obj2_2、…
以下1-7題與EMP、DEPT表有關。
如果沒有上述基本表,可以用下述SQL語句創建:
create table COUNTRIES as select * from univ.COUNTRIES;
create table DEPT as select * from univ.DEPT;
create table EMP as select * from univ.EMP;
1、輸出名爲SMITH的僱員的工資和職位。(存儲過程)
create or replace procedure obj2_1 as
vsal emp.sal%type; vjob emp.job%type;
begin
select sal,job into vsal, vjob from emp
where ename='SMITH';
dbms_output.put_line(vsal ||','|| vjob);
end;
.
/
set serveroutput on;
exec obj2_1;
2、傳送參數部門編號,輸出該部門名和地理位置。(存儲過程)
create or replace procedure obj2_2(z_deptno dept.deptno%type)
as z_dname dept.dname%type;
z_loc dept.loc%type;
begin
select dname,loc
into z_dname,z_loc
from dept
where deptno=z_deptno;
dbms_output.put_line(z_dname||' '||z_loc);
end;
.
/
exec obj2_2(30)
3、傳送參數僱員號,輸出該僱員的工資和提成,沒有提成的用0替代。(用%type實現)。(存儲過程)
create or replace procedure obj2_3(v_empno emp.empno%type)
as v_sal emp.empno%type;
v_comm emp.comm%type;
begin
select sal,nvl(comm,0)
into v_sal,v_comm
from emp
where empno=v_empno;
dbms_output.put_line(v_sal||' '||v_comm);
end;
.
/
set serveroutput on;
exec obj2_3(7369)
4、傳送參數僱員號,輸出該僱員的所有信息,沒有提成的用0替代。(用%rowtype實現)。(存儲過程)
create or replace procedure obj2_4(vempno emp.empno%type) as
row_emp emp%rowtype;
begin
select empno, ename,job,mgr, hiredate,nvl(sal,0),nvl(comm,0),deptno
into row_emp
from emp
where empno= vempno;
dbms_output.put(row_emp.empno||','||row_emp.ename||',');
dbms_output.put(row_emp.job||','||row_emp.mgr||',');
dbms_output.put(row_emp.hiredate||','||row_emp.sal||',');
dbms_output.put_line(row_emp.comm||','||row_emp.deptno);
end;
.
/
set serveroutput on;
exec obj2_4(7369)
5、傳送參數僱員號,返回該僱員的工資。(存儲函數)
create or replace function obj2_5(v_empno emp.empno%type)
return integer as v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno=v_empno;
return v_sal;
end;
.
/
select obj2_5(7369)from dual;
6、傳送參數僱員名或僱員編號,判斷他的job,根據job不同,爲他增加相應的sal(用if-elsif實現,不要改動到基本表emp,創建一個與emp表一模一樣的表emp1)。(存儲過程)
Job raise
clerk +500
salesman +1000
analyst +1500
otherwise +3000
create table emp1 as select * from emp;
create or replace
procedure obj2_6(vempno emp1.empno%type,vname emp1.ename%type) as
vsal emp1.sal%type; vjob emp1.job%type;
begin
select sal,job into vsal,vjob from emp1 where empno=vempno or ename=vname;
if vjob='CLERK' then vsal:=vsal+500;
elsif vjob='SALESMAN' then vsal:=vsal+1000;
elsif vjob='ANALYST' then vsal:=vsal+1500;
else vsal:=vsal+3000;
end if;
update emp1 set sal=vsal where (vempno=empno) or (ename=vname);
dbms_output.put_line(vname||'的工資已經更改爲:'||vsal);
end;
.
/
exec obj2_6(7369,'');
exec obj2_6('','SMITH');
7、傳送參數部門編號,按照下列加工資比例執行給該部門的僱員加工資(用CASE實現,修改emp1表的數據) (存儲過程)
deptno raise(%)
10 8%
20 10%
30 20%
40 20%
加薪比例以現有的sal爲標準。
create or replace
procedure obj2_7(vdeptno emp1.deptno%type) as
begin
case(vdeptno)
when 10 then update emp1 set sal=sal*1.08 where deptno=vdeptno;
when 20 then update emp1 set sal=sal*1.18 where deptno=vdeptno;
when 30 then update emp1 set sal=sal*1.20 where deptno=vdeptno;
when 40 then update emp1 set sal=sal*1.20 where deptno=vdeptno;
end case;
dbms_output.put_line(vdeptno||'部門的加薪已完成');
end;
.
/
set serveroutput on;
exec obj2_7(20);
以下8-12題與以下表有關:學生、學費標準表、收費表、收費明細表。先從a_db模式中將這些表等複製到自己的模式中。
學生每學年開學前必須註冊。開始註冊前要初始化學生表,所有狀態爲“註冊”的學生的狀態設置爲空值,註冊後設置爲"註冊",還有“畢業”、“開除”、“休學”等狀態。註冊時在收費表生成相應記錄。學生每學年按學生所屬專業收取學費,交學費時產生收費明細記錄,並修改收費表中相應記錄。
create table 學生 as select * from a_db.學生;
create table 學費標準表 as select * from a_db.學費標準表;
create table 收費表 as select * from a_db.收費表;
create table 收費明細表 as select * from a_db.收費明細表;
8、在學生表中增加一列,用來記錄學生的密碼,寫一個PL/SQL程序,模擬登錄的過程。輸入學號和密碼,判斷是否正確,對於登錄成功和失敗分別給出提示信息。(存儲過程)
增加密碼列
alter table 學生 add 密碼 varchar2(12);
創建了學生表的密碼列,設置密碼爲666
update 學生 set 密碼 = ‘666’,
create or replace
procedure obj2_8(v_學號 學生.學號%type,v_密碼 學生.密碼%type) as
vv_學號 學生.學號%type;
vv_密碼 學生.密碼%type;
begin
select 學號,密碼
into vv_學號,vv_密碼
from 學生
where v_學號=學號 and v_密碼=密碼;
dbms_output.put_line('登錄成功!');
exception
when no_data_found then
dbms_output.put_line('登陸失敗');
end;
9、編寫一個向學費標準表添加記錄的過程。
create or replace
procedure obj2_9 (
v_專業 學費標準表.專業%type,
v_學年 學費標準表.學年%type,
v_學費 學費標準表.學費%type) as
begin
insert into 學費標準表(專業, 學年, 學費)
values (v_專業, v_學年, v_學費);
dbms_output.put_line(v_專業||','||v_學年||','||v_學費||'添加完成');
end;
.
/
exec obj2_9('計算機科學與技術','2017','13000');
10、編寫一個學生註冊的過程,註冊日期默認爲當天,以學號爲參數。
create or replace
procedure obj2_10(v學號 學生.學號%type) as
begin
insert into 學生(學號,註冊日期) values (v學號,sysdate);
update 學生 set 狀態='註冊' where 學號=v學號 and 狀態='null';
dbms_output.put_line(v學號||'學生已在'|| to_char (sysdate,'yyyy-mm-dd')||'註冊成功');
end;
.
/
11、編寫一個收學費的過程,收費日期默認爲當天,以學年、 學號、學費爲參數。
create or replace
procedure obj2_11(
v_學年 收費明細表.學年%type,
v_學號 收費明細表.學號%type,
v_學費 收費明細表.學費%type) as
begin
insert into 收費明細表(學年,學號,學費) values (v_學年, v_學號, v_學費);
dbms_output.put_line('成功添加學生'||v_學號||'在'|| v_學年||'學年的付費記錄,共付款:'|| v_學費||'元');
end;
.
/
exec obj2_11('2019','S101',1300);
12、編寫一個過程,輸出指定學年的欠費情況(含欠費人數、欠費總金額)。
create or replace
procedure obj2_12(
v_學年 收費表.學年%type) as
total number(5);
money number(10);
begin
select count(學號),sum(應交學費-已交學費) a
into total,money
from 收費表
where 學年=v_學年 and 應交學費>已交學費;
dbms_output.put_line('欠費人數爲:'||total||' 欠費金額爲:'||money);
end;
.
/
exec obj2_12('2016');
select 學號,應交學費-已交學費 from 收費表 where 學年=2016 and 已交學費< 應交學費;
13、輸出如下九九乘法表。(存儲過程)
create or replace procedure obj2_13
as
i int;
j int;
begin
for i in 1..9 loop
for j in 1..i loop
dbms_output.put(i||'*'||j||'='||(i*j)||' ');
end loop;
dbms_output.put_line(' ');
end loop;
end;
.
/
exec obj2_13
三.實驗錯誤解決方案
問題一:創建的過程帶有編譯錯誤問題
1、問題的出現
在實驗項目2中創建“傳送參數部門編號,輸出該部門名和地理位置。(存儲過程)”,SQL語句如下:
create or replace
procedure obj2_2
(vdeptno in DEPT.dept%type)
as
vdname dept.dname%type;
vloc dept.loc%type;
begin
select dname,loc
into vdname,vloc
from dept
where deptno= vdeptno;
dbms_output.put_line(dname ||','|| loc);
end;
出現錯誤:
警告:創建的過程帶有編譯錯誤
2、問題分析
錯誤出現在第3行,表明“%type”定義數據類型有問題。使用由%TYPE定義的變量時要用“.”運算符指定表名限定詞,而且不用加“in”。但在第3行中由於C語言的語法干擾加了“in”,所以出錯。
3、解決方案
解決方案如下:
create or replace procedure obj2_2(z_deptno dept.deptno%type)
as z_dname dept.dname%type;
z_loc dept.loc%type;
begin
select dname,loc
into z_dname,z_loc
from dept
where deptno=z_deptno;
dbms_output.put_line(z_dname||' '||z_loc);
end;
.
/
exec obj2_2(30)
執行該語句後,表已創建,問題解決。