1. 程式人生 > >PL/SQL之儲存過程修改學生學號及觸發器實現一致性

PL/SQL之儲存過程修改學生學號及觸發器實現一致性

(1)建立三個表:Student(S#, Sname, age), Course(C#, cname, credit), SC(s#, c#, score),其中SC的S#和C#都是外來鍵,分別引用Student表的S#和Course表的C#。請首先在各自表中插入若干條記錄,然後用儲存過程實現修改指定學生的學號。

(2)建立兩個表:系表:Dept(D#, Dname, S_Count) ,其中S_count是每個系的學生人數;學生表:Stu(S#, Sname, age, D#) 其中D#是引用Dept(D#)的外來鍵。請用觸發器實現S_count和學生表中實際人數的一致性。

開發工具:PL/SQL Developer

1.建表:

Student(S#, Sname, age)表,對應SQL語句如下:

create table STUDENT
(
  S#    VARCHAR2(10) not null,
  Sname VARCHAR2(10),
  age   NUMBER,
  constraint S# primary key (S#)
);

Course(C#, cname, credit)表,對應SQL語句如下:

create table COURSE
(
  C#     VARCHAR2(10) not null,
  cname  VARCHAR2(20),
  credit NUMBER
, constraint C# primary key (C#) );

SC(s#, c#, score)表,對應SQL語句如下:

create table SC
(
  S#    VARCHAR2(5) not null,
  C#    VARCHAR2(5) not null,
  score NUMBER not nullconstraint SC_PK primary key (S#, C#),
  constraint C#_FK_COURSE foreign key (C#)
    references COURSE (C#) on delete cascade
, constraint S#_FK_STUDENT foreign key (S#) references STUDENT (S#) on delete cascade );

3.插入資料:

這裡由於需要一次性插入多條資料,而MySQL的多行插入語法INSERT INTO 某表 VALUES(各個值),VALUES(各個值);這樣會報錯,因為ORACLE不支援這種寫法;如果多個INSERT INTO VALUES(各個值);這樣以“;”隔開一同執行也是不行的,ORACLE也是不支援。

但是在這裡我們可以利用ORACLE 9i版本以後的語法,即”INSERT ALL INTO a表 VALUES(各個值) INTO a表 VALUES (其它值) INTO a表 VALUES(其它值) ….再跟一個SELECT 語句“。後邊跟的SELECT 語句我們可以從虛擬表裡查如 SELECT 1 FROM DUAL。

Student(S#, Sname, age)表,對應SQL語句如下:

insert all into student(s#,sname,age) values ('001','小A',20)
           into student(s#,sname,age) values ('002','小B',21)
           into student(s#,sname,age) values ('003','小C',20)
           into student(s#,sname,age) values ('004','小D',21)
           into student(s#,sname,age) values ('005','小E',20)
           select 1 from dual;
select * from student for update;

建表結果如下:

1

Course(C#, cname, credit)表,對應SQL語句如下:

insert all into course(c#,cname,credit) values ('1','資料庫',3.5)
           into course(c#,cname,credit) values ('2','人工智慧',3.5)
           into course(c#,cname,credit) values ('3','體系結構',3.5)
           into course(c#,cname,credit) values ('4','平行計算',3.5)
           into course(c#,cname,credit) values ('5','資訊保安',3)
           select 1 from dual;
select * from course for update;

建表結果如下:

2

SC(s#, c#, score)表,對應SQL語句如下:

insert all into sc(s#,c#,score) values ('001','1',90)
           into sc(s#,c#,score) values ('002','1',100)
           into sc(s#,c#,score) values ('003','1',80)
           select 1 from dual;
select * from sc for update;

建表結果如下:

3

4.編寫儲存過程,實現修改指定學生的學號:

由於我們在SC表中聲名了一個references Student(S#)的外來鍵約束和一個references Cousre(C#)的外來鍵約束,當我們修改Student表中的S#欄位時,需要更新SC表中的外來鍵約束。遺憾的是,在Oracle環境下,不能設定外來鍵為update級聯,所以只能進行人工處理了。

思路是先遮蔽SC表的外來鍵約束,然後修改Student表中的學號,並且在保證一致性的情況下更新所有SC中該學生的學號,最後恢復(或新增)SC表外來鍵約束。

儲存過程實現如下:

create or replace procedure Revise_S#(s#_old in varchar2, s#_new in varchar2) is

begin
  execute immediate 'alter table SC disable constraint s#_fk_student';
  update student set s# = s#_new where s#=s#_old;
  update sc set s# = s#_new where s#=s#_old;
  execute immediate 'alter table SC enable constraint s#_fk_student';  
end Revise_S#;

編寫SQL語句呼叫該儲存過程:

call Revise_S#('001','011');
select * from student;
select * from sc;

結果如下:

4

實現結果正確!

三.實驗(2)過程

1.建表:

系表:Dept(D#, Dname, S_Count),對應SQL語句如下:

create table DEPT
(
  D#      VARCHAR2(20) not null,
  Dname   VARCHAR2(20),
  S_Count NUMBER,
  constraint D# primary key (D#)
);

學生表:Stu(S#, Sname, age, D#),對應SQL語句如下:

create table STU
(
  S#    VARCHAR2(10) not null,
  Sname VARCHAR2(10),
  age   NUMBER,
  D#    VARCHAR2(20),
  constraint S# primary key (S#)
)

2.插入資料

系表:Dept(D#, Dname, S_Count),初始各個系的學生數設為0,對應SQL語句如下:

insert all into dept(d#,dname,s_count) values ('1','數學系',0)
           into dept(d#,dname,s_count) values ('2','物理系',0)
           into dept(d#,dname,s_count) values ('3','計算機系',0)
           select 1 from dual;
select * from dept for update;

3.建立觸發器

為保持S_count和學生表中實際人數的一致性,使用觸發器的new和old變數特性,具體實現如下:

create or replace trigger keep_s_count
  after insert or delete or update
  on stu 
  for each row

begin
  if deleting then
  update dept set s_count = s_count - 1
  where dept.d# = :old.d#;
  end if;

  if inserting then
  update dept set s_count = s_count + 1
  where dept.d# = :new.d#;
  end if;

  if updating('d#') then
   update dept set s_count = s_count - 1
   where dept.d# = :old.d#; 
    update dept set s_count = s_count + 1
   where dept.d# = :new.d#;
  end if;

end keep_s_count;

4.資料驗證
插入學生資訊:

insert all into stu(s#,sname,age,d#) values ('001','小A',20,'1')
           into stu(s#,sname,age,d#) values ('002','小B',21,'2')
           into stu(s#,sname,age,d#) values ('003','小C',20,'3')
           select 1 from dual;
select * from stu for update;
select * from dept;

結果如下:

5
數學系、物理系和計算機系的人數都變為了1,插入正確。

刪除學生資訊:

delete from stu where s#=001;
select * from dept;

結果如下:

6

刪去數學系學生之後,dept對應行的人數變為0,刪除正確。

修改學生資訊:

update stu set d#='3' where s#='002';
select * from dept;

結果如下:

7

修改物理系學生資訊為計算機系後,dept表對應的計算機系人數增加了,修改正確。