公司PL/SQL考覈及小結

一.數據庫初始化腳本

  1 -- Create table 學生信息
  2 drop table HAND_STUDENT;
  3 create table HAND_STUDENT
  4 (
  5   STUDENT_NO     VARCHAR2(10) not null,
  6   STUDENT_NAME   VARCHAR2(20),
  7   STUDENT_AGE    NUMBER(2),
  8   STUDENT_GENDER VARCHAR2(5)
  9 );
 10 -- Add comments to the table 
 11 comment on table HAND_STUDENT
 12   is '學生信息表';
 13 -- Add comments to the columns 
 14 comment on column HAND_STUDENT.STUDENT_NO
 15   is '學號';
 16 comment on column HAND_STUDENT.STUDENT_NAME
 17   is '姓名';
 18 comment on column HAND_STUDENT.STUDENT_AGE
 19   is '年齡';
 20 comment on column HAND_STUDENT.STUDENT_GENDER
 21   is '性別';
 22 -- Create/Recreate primary, unique and foreign key constraints 
 23 alter table HAND_STUDENT add primary key (STUDENT_NO);
 24 
 25 -- Create table 教師信息表
 26 drop table HAND_TEACHER;
 27 create table HAND_TEACHER
 28 (
 29   TEACHER_NO   VARCHAR2(10) not null,
 30   TEACHER_NAME VARCHAR2(20),
 31   MANAGER_NO   VARCHAR2(10)
 32 );
 33 -- Add comments to the table 
 34 comment on table HAND_TEACHER
 35   is '教師信息表';
 36 -- Add comments to the columns 
 37 comment on column HAND_TEACHER.TEACHER_NO
 38   is '教師編號';
 39 comment on column HAND_TEACHER.TEACHER_NAME
 40   is '教師名稱';
 41 comment on column HAND_TEACHER.MANAGER_NO
 42   is '上級編號';
 43 -- Create/Recreate primary, unique and foreign key constraints 
 44 alter table HAND_TEACHER add primary key (TEACHER_NO);
 45 
 46 -- Create table 課程信息表
 47 drop table HAND_COURSE;
 48 create table HAND_COURSE
 49 (
 50   COURSE_NO   VARCHAR2(10) not null,
 51   COURSE_NAME VARCHAR2(20),
 52   TEACHER_NO  VARCHAR2(20) not null
 53 );
 54 -- Add comments to the table 
 55 comment on table HAND_COURSE
 56   is '課程信息表';
 57 -- Add comments to the columns 
 58 comment on column HAND_COURSE.COURSE_NO
 59   is '課程號';
 60 comment on column HAND_COURSE.COURSE_NAME
 61   is '課程名稱';
 62 comment on column HAND_COURSE.TEACHER_NO
 63   is '教師編號';
 64 -- Create/Recreate primary, unique and foreign key constraints 
 65 alter table HAND_COURSE add constraint PK_COURSE primary key (COURSE_NO, TEACHER_NO);
 66 
 67 -- Create table 成績信息表
 68 drop table HAND_STUDENT_CORE;
 69 create table HAND_STUDENT_CORE
 70 (
 71   STUDENT_NO VARCHAR2(10) not null,
 72   COURSE_NO  VARCHAR2(10) not null,
 73   CORE       NUMBER(4,2)
 74 );
 75 -- Add comments to the table 
 76 comment on table HAND_STUDENT_CORE
 77   is '學生成績表';
 78 -- Add comments to the columns 
 79 comment on column HAND_STUDENT_CORE.STUDENT_NO
 80   is '學號';
 81 comment on column HAND_STUDENT_CORE.COURSE_NO
 82   is '課程號';
 83 comment on column HAND_STUDENT_CORE.CORE
 84   is '分數';
 85 -- Create/Recreate primary, unique and foreign key constraints 
 86 alter table HAND_STUDENT_CORE add constraint PK_SC primary key (STUDENT_NO, COURSE_NO);
 87 
 88 -- Create table 學生歷史信息表
 89 drop table HAND_STUDENT_HIS;
 90 create table HAND_STUDENT_HIS
 91 (
 92   STUDENT_NO       VARCHAR2(10) not null,
 93   STUDENT_NAME     VARCHAR2(20),
 94   STUDENT_AGE      NUMBER(2),
 95   STUDENT_GENDER   VARCHAR2(5),
 96   LAST_UPDATE_DATE DATE,
 97   STATUS           VARCHAR2(5)
 98 );
 99 -- Add comments to the table 
100 comment on table HAND_STUDENT_HIS
101   is '學生信息歷史表';
102 -- Add comments to the columns 
103 comment on column HAND_STUDENT_HIS.STUDENT_NO
104   is '學號';
105 comment on column HAND_STUDENT_HIS.STUDENT_NAME
106   is '姓名';
107 comment on column HAND_STUDENT_HIS.STUDENT_AGE
108   is '年齡';
109 comment on column HAND_STUDENT_HIS.STUDENT_GENDER
110   is '性別';
111 comment on column HAND_STUDENT_HIS.LAST_UPDATE_DATE
112   is '最後更新時間';
113 comment on column HAND_STUDENT_HIS.STATUS
114   is '狀態';
115   
116 -- Create table 日誌信息表
117 drop table HAND_LOG;
118 create table HAND_LOG
119 (
120   CODE             VARCHAR2(240) not null,
121   MSG              VARCHAR2(240) not null,
122   KEY1             VARCHAR2(240),
123   KEY2             VARCHAR2(240),
124   KEY3             VARCHAR2(240),
125   KEY4             VARCHAR2(240),
126   KEY5             VARCHAR2(240)
127 );
128 -- Add comments to the table 
129 comment on table HAND_LOG
130   is '日誌信息表';
131 -- Add comments to the columns 
132 comment on column HAND_LOG.CODE
133   is '編號';
134 comment on column HAND_LOG.MSG
135   is '消息';
136 comment on column HAND_LOG.KEY1
137   is '關鍵字1';
138 comment on column HAND_LOG.KEY2
139   is '關鍵字2';
140 comment on column HAND_LOG.KEY3
141   is '關鍵字3';
142 comment on column HAND_LOG.KEY4
143   is '關鍵字4';
144 comment on column HAND_LOG.KEY5
145   is '關鍵字5';
146 
147 /*******初始化學生表的數據******/
148 insert into HAND_STUDENT values ('s001','張三',23,'');
149 insert into HAND_STUDENT values ('s002','李四',23,'');
150 insert into HAND_STUDENT values ('s003','吳鵬',25,'');
151 insert into HAND_STUDENT values ('s004','琴沁',20,'');
152 insert into HAND_STUDENT values ('s005','王麗',20,'');
153 insert into HAND_STUDENT values ('s006','李波',21,'');
154 insert into HAND_STUDENT values ('s007','劉玉',21,'');
155 insert into HAND_STUDENT values ('s008','蕭蓉',21,'');
156 insert into HAND_STUDENT values ('s009','陳蕭曉',23,'');
157 insert into HAND_STUDENT values ('s010','陳美',22,'');
158 commit;
159 /******************初始化教師表***********************/
160 insert into HAND_TEACHER values ('t001', '劉陽','');
161 insert into HAND_TEACHER values ('t002', '諶燕','t001');
162 insert into HAND_TEACHER values ('t003', '胡明星','t002');
163 commit;
164 /***************初始化課程表****************************/
165 insert into HAND_COURSE values ('c001','J2SE','t002');
166 insert into HAND_COURSE values ('c002','Java Web','t002');
167 insert into HAND_COURSE values ('c003','SSH','t001');
168 insert into HAND_COURSE values ('c004','Oracle','t001');
169 insert into HAND_COURSE values ('c005','SQL SERVER 2005','t003');
170 insert into HAND_COURSE values ('c006','C#','t003');
171 insert into HAND_COURSE values ('c007','JavaScript','t002');
172 insert into HAND_COURSE values ('c008','DIV+CSS','t001');
173 insert into HAND_COURSE values ('c009','PHP','t003');
174 insert into HAND_COURSE values ('c010','EJB3.0','t002');
175 insert into HAND_COURSE values ('c011','PHP','t004');
176 commit;
177 /***************初始化成績表***********************/
178 insert into HAND_STUDENT_CORE values ('s001','c001',58.9);
179 insert into HAND_STUDENT_CORE values ('s002','c001',80.9);
180 insert into HAND_STUDENT_CORE values ('s003','c001',81.9);
181 insert into HAND_STUDENT_CORE values ('s004','c001',60.9);
182 insert into HAND_STUDENT_CORE values ('s001','c002',82.9);
183 insert into HAND_STUDENT_CORE values ('s002','c002',72.9);
184 insert into HAND_STUDENT_CORE values ('s003','c002',81.9);
185 insert into HAND_STUDENT_CORE values ('s001','c003','59');
186 insert into HAND_STUDENT_CORE values ('s003','c011',81.9);
187 insert into HAND_STUDENT_CORE values ('s001','c011','59');
188 commit;
View Code

二.PL/SQL練習題

  1.建立一個 package,命名爲 cux_exam_工號_pkg,包含如下內容: 

    1.1聲明一個 recoder 數據類型命名爲 type_studens_rec,包含如下字段:

 

    1.2 基於上面的記錄聲明一個內存表類型,命名爲 type_studens_tbl。

    1.3建立一個方法,返回類型爲 type_studens_tbl,取出分數低於課程平均分 的學生信息:學號、姓名、課程編號、課程名、教師、分數、課程平均分、 課程最高分、最低分。

    1.4建立一個過程,調用上面的方法,輸出這些學生中,給全部成績低於平均分 的學生加 1 分(更新成績表),若是加分後的學生成績低於 60 分,則輸出這 個學生的信息。處理成功則返回 S 狀態並提交事物;失敗則返回 E 狀態及 回錯誤消息,同時回滾事物。

    1.5建立一個方法,根據參數的教師編號,返回這個教師的直接領導的教師編 號。若是不存在,返回-1, 若是存在多條記錄,返回-2,若是存在其餘異 常,返回-3。

    1.6建立一個公共方法,根據參數 課程編號,返回該課程學生的及格率,返回 類型爲數字,保留兩位小數(及格率=課程成績在 60 分以上的同窗人數/課 程總人數)。

    1.7寫一個匿名塊,建立一張臨時表,hand_teacher_temp(動態 SQL), 結構 與 hand_teacher 相同。取全部課程及格率高於 50%的教師信息,插入到hand_teacher_temp 表中。(使用前面程序中求及格率的函數)。

    1.8 寫一個匿名塊,更新學生所選課程的成績。若是存在課程成績在 60 分以 上,則對原成績降分 2%,輸出學生編號,課程編號以及更新後的成績(用 returning into )。

    題解:sql

      包頭(1.1~1.6):數據庫

create or replace package cux_exam_xxxx_pkg is
-- 1. 定義數據類型
type score_data_type is record(
student_no hand_student.student_no%type,
student_name hand_student.student_name%type,
student_age hand_student.student_age%type,
student_gender hand_student.student_gender%type,
course_no hand_course.course_no%type,
course_name hand_course.course_name%type,
teacher_name hand_teacher.teacher_name%type,
core hand_student_core.core%type,
avg_core hand_student_core.core%type,
max_core hand_student_core.core%type,
min_core hand_student_core.core%type);
-- 2. 定義內存表類型 type_studens_tbl
TYPE type_studens_tbl IS TABLE OF studens_rec%ROWTYPE INDEX BY
BINARY_INTEGER;
-- 3. 得到低於平均分數的學⽣生信息
function get_grounded_info return type_studens_tbl;
-- 4. 分數調整
procedure score_adjustment(p_std_score in number,
x_return_status out nocopy varchar2,
x_msg_data out nocopy varchar2);
-- 5. 查詢教師的直接領導
function get_manager(p_teacher_no in varchar2) return varchar2 ;
-- 6. 查詢課程的及格率
function get_course_pass_rate(p_course_no in varchar2) return
number ;
end cux_exam_xxxx_pkg;

      包體(1.1~1.6):數組

  1 create or replace package body cux_exam_xxxx_pkg is
  2 -- 3. 得到低於平均分數的學⽣生信息
  3 function get_grounded_info return type_studens_tbl is
  4 l_studens_tbl type_studens_tbl;
  5 begin
  6 -- 計算每⻔門課程的平均分,並取出全部成績低於平均分的學⽣生
  7 select *
  8 from (select hs.student_no,
  9 hs.student_name,
 10 hs.student_age,
 11 hs.student_gender,
 12 hc.course_no,
 13 hc.course_name,
 14 ht.teacher_name,
 15 hsc.core,
 16 round(avg(hsc.core) over(partition by
 17 hsc.course_no), 2) avg_core,
 18 max(hsc.core) over(partition by hsc.course_no)
 19 max_core,
 20 min(hsc.core) over(partition by hsc.course_no)
 21 min_core
 22 from hand_course hc,
 23 hand_student hs,
 24 hand_student_core hsc,
 25 hand_teacher ht
 26 where hc.course_no = hsc.course_no
 27 and hs.student_no = hsc.student_no
 28 and hc.teacher_no = ht.teacher_no)
 29 BULK COLLECT into l_studens_tbl
 30 where core < avg_core;
 31 return l_studens_tbl;
 32 end get_grounded_info;
 33 -- 4. 分數調整
 34 procedure score_adjustment(p_std_score in number,
 35 x_return_status out nocopy varchar2,
 36 x_msg_data out nocopy varchar2) is
 37 l_data_cur ref_cursor;
 38 l_data_rec score_data_type;
 39 l_new_score number;
 40 l_savepoint_name varchar2(30) := 'sp_score_adjustment';
 41 begin
 42 x_return_status := 'S';
 43 x_msg_data := null;
 44 savepoint l_savepoint_name;
 45 l_data_cur := get_grounded_info;
 46 loop
 47 fetch l_data_cur
 48 into l_data_rec;
 49 exit when l_data_cur%notfound;
 50 update hand_student_core hsc
 51 set hsc.core = nvl(hsc.core, 0) + 1
 52 where hsc.student_no = l_data_rec.student_no
 53 and hsc.course_no = l_data_rec.course_no
 54 returning hsc.core into l_new_score;
 55 if l_new_score < nvl(p_std_score, 60) then
 56 dbms_output.put_line('Student No.: ' ||
 57 l_data_rec.student_no ||
 58 ', Student Name: ' ||
 59 l_data_rec.student_name ||
 60 ', Course Name: ' ||
 61 l_data_rec.course_name ||
 62 ', Teacher Name: ' ||
 63 l_data_rec.teacher_name ||
 64 ', Score: ' || l_data_rec.core ||
 65 ', Avg score: ' || l_data_rec.avg_core
 66 ||
 67 ', Max score: ' || l_data_rec.max_core
 68 ||
 69 ', Min score: ' ||
 70 l_data_rec.min_core);
 71 end if;
 72 end loop;
 73 commit;
 74 exception
 75 when others then
 76 rollback to l_savepoint_name;
 77 x_return_status := 'E';
 78 x_msg_data := substr(sqlerrm, 1, 2000);
 79 end score_adjustment;
 80 -- 5. 查詢教師的直接領導
 81 function get_manager(p_teacher_no in varchar2) return varchar2 is
 82 l_teacher_no hand_teacher.teacher_no%type;
 83 begin
 84 select ht.teacher_no
 85 into l_teacher_no
 86 from hand_teacher ht
 87 where level = 2
 88 connect by ht.teacher_no = prior ht.manager_no
 89 start with ht.teacher_no = p_teacher_no;
 90 return l_teacher_no;
 91 exception
 92 when no_data_found then
 93 return '-1';
 94 when too_many_rows then
 95 return '-2';
 96 when others then
 97 return '-3';
 98 end get_manager;
 99 -- 6. 查詢課程及格率
100 function get_course_pass_rate(p_course_no in varchar2) return
101 number is
102 l_passed_count number;
103 l_total_count number;
104 l_course_pass_rate number;
105 begin
106 select sum(case
107 when hsc.core > 60
108 then 1
109 else
110 0
111 end) passed_count, count(1) total_count
112 Into l_passed_count, l_total_count
113 from hand_student_core hsc
114 where hsc.course_no = p_course_no;
115 l_course_pass_rate := round(l_passed_count/l_total_count,2);
116 return l_course_pass_rate;
117 exception
118 when others then
119 return null;
120 end get_course_pass_rate;
121 end cux_exam_XXXX_pkg;
View Code

 

      1.7:安全

-- 7.取全部課程及格率⾼高於50%的教師信息,插⼊入到 hand_teacher_temp 表中。
declare
l_count number;
begin
select count(1)
into l_count
from all_tables t
where t.TABLE_NAME = 'HAND_TEACHER_TEMP';
if l_count > 0 then
execute immediate 'DROP TABLE HAND_TEACHER_TEMP';
end if;
execute immediate 'CREATE TABLE HAND_TEACHER_TEMP AS ' ||
insert hand_teacher_temp
select *
from hand_teacher ht
where not exists(
select 1
from hand_course hc
where cux_exam_xxxx_pkg.get_grounded_info(hc.course_no)
<0.5
and hc.teacher_no = ht.teacher_no)';
exception
when others then
dbms_output.put_line(sqlcode || '-' || sqlerrm);
end;

 

      1.8:  app

-- 8. 寫⼀一個匿匿名塊,更更新學⽣生所選課程的成績。若是存在課程成績在 60 分以 上,則對
原成績降分 2%,輸出學⽣生編號,課程編號以及更更新後的成績(⽤用 returning into )(10
分)
Declare
TYPE type_student_core_tb IS TABLE OF hand_student_core%ROWTYPE;
l_student_core_tb type_student_core_tb;
begin
Update hand_student_core t
set t.core = t.core * 0.98
Where t.core >60
RETURNING student_no ,course_no, core BULK COLLECT INTO
l_student_core_tb;
FOR i IN l_student_core_tb.FIRST .. l_student_core_tb.LAST
LOOP
DBMS_OUTPUT.PUT_LINE( l_student_core_tb(i). student_no || ' '||
l_student_core_tb(i). course_no || ' '|| l_student_core_tb(i).
core );
END LOOP;
commit;
exception
when others then
rollback;
dbms_output.put_line(sqlcode || '-' || sqlerrm);
end;

    小結:ide

      注函數和存儲過程的區別:函數有返回值,存儲過程沒有返回值,函數參數只能是INT類型(傳入參數),存儲過程能夠是INT,OUT,IN OUT;函數

      大多數SQL函數能在PL/SQL中過程語句中使用,如單行的數值和字符串函數、數據類型轉換函數、日期函數、時間函數、求最大、最小值的 GREATEST, LEAST 函數等,可是有些函數不能再PL/SQL中使用,如Decode函數、分組函數(AVG, MIN, MAX, COUNT, SUM, STDDEV, and VARIANCE)等;oop

      PLSQL的塊是能夠嵌套的,變量的做用範圍與其餘語言相似 ,若是同名,想要訪問外層的須要使用outer關鍵字;fetch

      PLSQL中經常使用的自定義類型就兩種: 記錄類型、PLSQL內存表類型(根據表中的數據字段的簡單和複雜 程度又可分別實現相似於簡單數組和記錄數組的功能);spa

      意外處理等,內置異常,以及raise_application_error()函數等注意。。。 

  2.(1) 建立一個歷史表 hand_teacher_his, 其中包括 hand_teacher 表的所 有字段, 新增 last_update_date(處理日期)以及 operation(操做類 型)兩列 。

     (2) 在 hand_teacher 表上面建立一個觸發器,記錄表的新增,更新(記錄更 新前的數據)和刪除(記錄刪除前的數據)操做,並記錄操做類型和處理日期。 

  題解:

    (1):

-- 2-1. 建立⼀一個 hand_teacher_his 歷史表
create table hand_teacher_his
as
select ht.*, sysdate last_update_date, 'U' operation
from hand_teacher ht
where 1=-1;

    (2):

-- 2-2. 在 hand_teacher 表上新建⼀一個觸發器器
create or replace trigger hand_teacher_tgr1
after insert or update or delete on hand_teacher
for each row
declare
begin
if inserting then
insert into hand_teacher_his
values(:new.teacher_no, :new.teacher_name, :new.manager_no,
sysdate, 'I');
elsif updating then
insert into hand_teacher_his
values(:old.teacher_no, :old.teacher_name, :old.manager_no,
sysdate, 'U');
elsif deleting then
insert into hand_teacher_his
values(:old.teacher_no, :old.teacher_name, :old.manager_no,
sysdate, 'D');
end if;
exception
when others then
raise_application_error(-20005, sqlcode ||'-' ||sqlerrm );
end;

 

    小結:

      觸發器注意:時機:Before 或者 After 或 Instead of 事件:Insert 或 Update 或 Delete 對象:表名(或視圖名) 類型:Row 或者 Statement級; 條件:知足特定Where條件才執行; 內容:一般是一段PLSQL塊代碼; 

            重點注意: Instead of : 用Trigger的內容替換 事件自己的動做 Row級:SQL語句影響到的每一行都會引起Trigger Statement級:一句SQL語句引起一次,無論它影響多少行(甚至0行)。

  3. 寫一個匿名塊,在 system(system/manager)用戶下執行。 新建一個 directory : HAND_DIR_TEMP_XXXX , 物理地址爲虛擬機的 c:\temp 目錄, 並受權 讀寫 權限給 student1 用戶,而後將 hand_exam_data.txt 這個 文件放到 c:\temp 目錄下。(xxxx 爲本身的工號):  

-- 3. 使⽤用system ⽤用戶新建⼀一個 directory
begin
execute immediate 'create or replace directory HAND_DIR_TEMP as
''c:\temp''';
execute immediate 'grant read ,write on directory HAND_DIR_TEMP to
student1';
end;

 

    小結:

      Oracle Directory是爲了便於控制Bfile存儲的安全性;

      在Oracle 內部建立的 Directory 默認的全部者是sys, 並有DBA( 或者是另外一個擁有 CREATE ANY DIRECTORY 權限的用戶)建立;Directory 對象能夠像表那樣給其餘用戶賦權。 

  4.從 hand_exam_data.txt 文件讀取內容並導入到 hand_teacher 表。要求: (1) 從數據文件中讀取數據,並按照逗號分隔符進行拆分,提取字段的值。 (2) 去掉數據中的雙引號 (3) 將處理後的數據,插入到 hand_teacher 表 :

 1 -- 3. 從hand_exam_data.txt⽂文件讀取內容並導⼊入到 hand_teacher 表
 2 declare
 3 l_line VARCHAR2(1023);
 4 fid UTL_FILE.FILE_TYPE;
 5 l_data_rec hand_teacher%rowtype;
 6 procedure split_columns(p_data_str in varchar2,
 7 x_data_rec out hand_teacher%rowtype) is
 8 l_substr varchar2(2000);
 9 l_instr number;
10 begin
11 if p_data_str is null then
12 return;
13 end if;
14 l_substr := p_data_str;
15 l_instr := instr(l_substr, ',');
16 x_data_rec.teacher_no := trim(replace(substr(l_substr, 1,
17 l_instr - 1),'"',''));
18 -- 提取teacher_name
19 l_substr := substr(l_substr, l_instr + 1);
20 l_instr := instr(l_substr, ',');
21 x_data_rec.teacher_name := trim(replace(substr(l_substr, 1,
22 l_instr - 1),'"',''));
23 -- 提取manager_no
24 l_substr := substr(l_substr, l_instr + 1);
25 l_instr := instr(l_substr, ',');
26 x_data_rec.manager_no := trim(replace(l_substr,'"',''));
27 end;
28 BEGIN
29 BEGIN
30 fid := UTL_FILE.FOPEN('HAND_DIR_TEMP', 'hand_exam_data.txt',
31 'R');
32 loop
33 UTL_FILE.GET_LINE(fid, l_line);
34 dbms_output.put_line(l_line);
35 split_columns(l_line, l_data_rec);
36 if l_data_rec.teacher_no is not null then
37 insert into hand_teacher values l_data_rec;
38 end if;
39 end loop;
40 utl_file.fclose(fid);
41 EXCEPTION
42 WHEN NO_DATA_FOUND THEN
43 if utl_file.is_open(fid) then
44 utl_file.fclose(fid);
45 end if;
46 END;
47 commit;
48 EXCEPTION
49 WHEN others THEN
50 rollback;
51 dbms_output.put_line(sqlcode || '-' || sqlerrm);
52 END;
View Code

    小結:

這裏注意打開文件函數 UTL_FILE.FOPEN,讀取內容函數 UTL_FILE.GET_LINE,以及什麼時候不在讀取(爲null),以及異常處理,內容格式處理。

相關文章
相關標籤/搜索