Oracle入門--day5--PLSQL - 概覽、塊、SQL語句等

知識點概覽:

PLSQL 概覽、PLSQL 的塊概念、PLSQL變量|、PLSQL 中的SQL語句、

PLSQL 的控制語法、PLSQL 中的複雜自定義數據類型、

PLSQL 中的遊標、PLSQL 的例外處理、PLSQL 中的存儲過程和函數

 

知識點講解:

PLSQL 概覽:

PLSQL 是Oracle 公司在SQL 基礎上進行擴展而成的一種過程語言。PLSQL 提供了典型的高級語言特
性,包括封裝,例外處理機制,信息隱藏,面向對象等;並把最新的編程思想帶到了數據庫服務器和工具
集中。

與 與Java, C# 相比 , ,PLSQL 的優勢是:SQL 語言可以直接寫到PLSQL 的“塊”中或者是PLSQL 的過程、
向 函數中。沒有必要向java 那樣先創建Statement 對象來執行SQL; 這使得PLSQL 成爲很強大的事務處理語
用 言,即:使用SQL 來處理數據,使用控制結構來處理業務邏輯。

PLSQL 在Oracle 數據庫服務器(在存儲過程、函數、數據庫觸發器,Package 包中使用)和Oracle 開發
工具集(在; 開發工具組件的觸發器中使用);Form Developer ,Report Developer 還可以使用共享庫
(包含使用PLSQL 寫的過程和函數,擴展名爲PLL 的文件); SQL 數據類型也可以在PLSQL 中使用,結合
SQL 提供者的直接訪問,這些共享數據類型整合了PLSQL 和Oracle 的數據庫字典。PLSQL 消除了存取數據
庫的便利性與過程語言之間的障礙。

 

PLSQL 的另一個顯著好處在於它可以通過減少來回交互減輕網絡流量壓力、節省時間:

PLSQL塊概念

PLSQL 是一種類PASCAL 語言,每一段程序都是由Block 組成的:

DECLARE (Optional)
Variables, cursors, user-defined exceptions
BEGIN (Mandatory)
 SQL statements
 PL/SQL statements
EXCEPTION (Optional)
Actions to perform when errors occur
END; (Mandatory)

使用分號作爲一句SQL 或者PLSQL 語句的結束;

塊結構關鍵字(DECLARE, BEGIN,EXCEPTION 後面不跟分號;

END 後面需帶分號;

你可以把一句SQL 語句寫在一行上,但一般不建議這麼做,因爲代碼不夠漂亮!

 

PLSQL 的塊包括三種:匿名塊、存儲過程、函數;

PLSQL 的變量

PLSQL 的變量類型:

1 、系統內置的常規簡單變量類型: 比如大多數 數據庫表的字段類型都可以作爲變量類型;
2、用戶自定義複雜變量類型: 比如記錄類型;
3 、引用類型:保存了一個指針值;
4 、大對象類型(LOB ):保存了一個指向大對象的地址;

 

PLSQL 的變量 類型舉例:

布爾類型  數值類型  BFILE類型  日期類型 BLOB類型  LONG類型  字符串類型

 

SQLPLUS 變量

PLSQL 本身沒有輸入輸出功能,如果要想 像命令行運行C 程序那樣可以接收輸入值,那你必須依賴執行環境
把值傳給PLSQL 塊,比如iSQL Plus 執行環境或者PLSQL Developer 的Command Window 執行環境中,
種 有一種substitution 變量 可以用來接收輸入值;而另一種Host 變量可以把運行時的值傳出到執行環境中。
關 有關SQLPLUS 變量,我們會在以後詳細展開;

 

PLSQL的 的 變量聲明語法:

identifier [CONSTANT] datatype [NOT NULL]
[:= | DEFAULT expr];

說明:
1 、變量命名建議遵循通用規則,比如v_name 表示一個變量,c_name 表示一個常量;
2 、一般建議每一行聲明一個變量,這樣程序的可讀性比較好;
3 、如果聲明瞭變量,但未進行初始化,則在沒有賦值之前該變量的值爲NULL; 一個好的編程習慣是對所有聲明
的變量進行初始化賦值。

4 、在同一個塊中,避免命名與數據庫表中的字段名相同的變量;

 

PLSQL 特有的%TYPE 屬性來聲明與XX 類型一致的變量類型:

identifier Table.column_name%TYPE;

可綁定變量( (Bind Variable 也稱爲Host Variable , 非PLSQL 變量):

VARIABLE g_salary NUMBER
BEGIN
    SELECT salary
    INTO :g_salary
    FROM employees
    WHERE employee_id = 178;
END;
/
PRINT g_salary

可綁定變量是一種在縮主環境中定義的變量,所謂 縮主 環境一般指示SQLPLUS 執行環境或者是
PLSQL Developer 的Command Window 執行環境;可綁定變量可用於在運行時把值傳遞給PLSQL, 創建語法:
VARIABLE return_code NUMBER
VARIABLE return_msg VARCHAR2(30)
的 大家注意,在標準的PLSQL 中定義變量是不能用VARIABLE 關鍵字的,此關鍵字只在SQLPLUS 執行環境中有效,
可使用PRINT 語句輸出變量內容。
在PLSQL 中使用這種變量時,前面加”:”, 以示區分。

 

DBMS_OUTPUT.PUT_LINE() 介紹:

在接下來的實驗中,經常需要在調試程序時輸出中間變量的值,我們可使用Oracle 內置的Package 中的函數:

DECLARE
v_sal NUMBER(9,2) := &p_annual_sal;
BEGIN
v_sal := v_sal/12;
DBMS_OUTPUT.PUT_LINE ('The monthly salary is ' ||
TO_CHAR(v_sal));
END;

上述例子中,我們使用DBMS_OUTPUT.PUT_LINE () 輸出變量v_sal 的值;
解釋:&p_annual_sal 在Plsql Developer 的SQL window 執行環境中,可用於提示用戶輸入一個具體
的值。
注意:在SQLPLUS 中執行DBMS_OUTPUT.PUT_LINE () 前,必須先執行:
SET SERVEROUTPUT ON ,而在PLSQL Developer 的SQL Window 中則不需要這句話。

 

PLSQL 中的註釋語句:
1 、多行註釋類似於java 或者 C , , 用 使用 /* 和 和 */
2 、單行註釋是在語句後面使用–

 

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

 

塊嵌套和變量範圍:
PLSQL的塊是可以嵌套的,變量的作用範圍與其他語言類似

 

變量限定詞: 假設我們在塊嵌套的程序中,裏層和外層有相同的變量聲明,而裏層的程序要訪問外層的同名變量
該怎麼辦呢?
答案是:使用塊限定詞,請看例子:

<<outer>>
    DECLARE
        birthdate DATE;
    BEGIN
        DECLARE
            birthdate DATE;
        BEGIN
            ...
            outer.birthdate :=
                TO_DATE( ' 03-AUG-1976 ' ,
                    ' DD-MON-YYYY ' );
        END;
    ....
    END;

這個例子中,birthdate 是同名變量,限定詞outer 表示外層,裏層要訪問外層的bithdate 時使用
outer.birthdate這種格式

 

PLSQL中的SQL語句:

SELECT INTO 語句: 用於把從數據庫查詢出內容存入變量

DECLARE
    v_hire_date employees.hire_date%TYPE;
    v_salary employees.salary%TYPE;
BEGIN
    SELECT hire_date, salary
    INTO v_hire_date, v_salary
    FROM employees
    WHERE employee_id = 100;
    ...
END;
/

 

注意點:該語句支持單行的查詢結果,果 如果Where 條件控制不好,導致多行查詢結果,則會引發Too_many_rows的例外

 

INSERT 、UPDATE 、DELETE 、MERGE 語句:

在 PLSQL 中執行這些SQL 語句和直接執行這些語句差不多,只不過可以在SQL 語句中使用PLSQL聲明的變量;

BEGIN
INSERT INTO employees
(employee_id, first_name, last_name, email,
hire_date, job_id, salary)
VALUES
(employees_seq.NEXTVAL, 'Ruth', 'Cores', 'RCORES',
sysdate, 'AD_ASST', 4000);
END;
/
DECLARE
v_sal_increase employees.salary%TYPE := 800;
BEGIN
UPDATE employees
SET salary = salary + v_sal_increase
WHERE job_id = 'ST_CLERK';
END;
/
DECLARE
v_deptno employees.department_id%TYPE := 10;
BEGIN
DELETE FROM employees
WHERE department_id = v_deptno;
END;
/
DECLARE
v_empno employees.employee_id%TYPE := 100;
BEGIN
MERGE INTO copy_emp c
USING employees e
ON (e.employee_id = v_empno)
WHEN MATCHED THEN
UPDATE SET
c.first_name = e.first_name,
c.last_name = e.last_name,
c.email = e.email,
. . .
WHEN NOT MATCHED THEN
INSERT VALUES(e.employee_id, e.first_name, e.last_name,
. . .,e.department_id);
END;

 

PLSQL中的控制語句

和其他語言一樣,控制主要包括判斷和循環;
判斷語句的語法與其他語言類似:

IF condition THEN
statements;
[ELSIF condition THEN
statements;]
[ELSE
statements;]
END IF;
CASE selector
WHEN expression1 THEN result1
WHEN expression2 THEN result2
...
WHEN expressionN THEN resultN
[ELSE resultN+1;]
END;

需要注意的是對NULL的判斷處理:一般人容易犯錯誤或者不容易記住

 

循環語句的語法與其他語言類似:有基本循環、For 循環、Wihle循環三種

LOOP
statement1;
. . .
EXIT [WHEN condition];
END LOOP;
WHILE condition LOOP
statement1;
statement2;
. . .
END LOOP;
FOR counter IN [REVERSE]
lower_bound..upper_bound LOOP
statement1;
statement2;
. . .
END LOOP;

嵌套循環和Label

...
BEGIN
<<Outer_loop>>
LOOP
v_counter := v_counter+1;
EXIT WHEN v_counter>10;
<<Inner_loop>>
LOOP
...
EXIT Outer_loop WHEN total_done = 'YES';
-- Leave both loops
EXIT WHEN inner_done = 'YES';
-- Leave inner loop only
...
END LOOP Inner_loop;
...
END LOOP Outer_loop;
END;

Label 一般用不着,只有在使用goto 語句,或者內部循環需要訪問外部的同名變量的時候才需要,而一般這
種做法也是不被提倡的。

 

PLSQL中的複雜自定義數據類型(類似Java構造器感覺)

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

記錄類型的定義語法:

TYPE type_name IS RECORD
(field_declaration[, field_declaration]…);
identifier type_name;

這裏的field_declaration 的具體格式可以是:

field_name {field_type | variable%TYPE
| table.column%TYPE | table%ROWTYPE}
[[NOT NULL] {:= | DEFAULT} expr]

%ROWTYPE 屬性:在PLSQL 中 %ROWTYPE 表示某張表的記錄類型 或者是用戶指定以的記錄類型,使用此
屬性可以很方便的定義一個變量,其類型與某張表的記錄或者自定義的記錄類型保持一致。極大的方便了
Select * into ….的語句實用

舉例:

DECLARE
emp_rec employees%ROWTYPE;
BEGIN
SELECT * INTO emp_rec
FROM employees
WHERE employee_id = &employee_number;
INSERT INTO retired_emps(empno, ename, job, mgr, hiredate,
leavedate, sal, comm, deptno)
VALUES (emp_rec.employee_id, emp_rec.last_name, emp_rec.job_id,
emp_rec.manager_id, emp_rec.hire_date, SYSDATE, emp_rec.salary,
emp_rec.commission_pct, emp_rec.department_id);
COMMIT;
END;
/

PLSQL 內存表即Index By Table , 這種結構類似於數組,使用主鍵提供類似於數組那樣的元
素訪問。: 這種類型必須包括兩部分:1 、使用BINARY_INTEGER ; 類型構成的索引主鍵; 2 、另外一個簡單類型
。 或者用戶自定義類型的字段作爲具體的數組元素。 這種類型可以自動增長,所以也類似於可變長數組。

語法:

TYPE type_name IS TABLE OF
{column_type | variable%TYPE
| table.column%TYPE} [NOT NULL]
| table.%ROWTYPE
[INDEX BY BINARY_INTEGER];
identifier type_name;

PLSQL 內存表應用舉例:

下面定義的兩個內存表中的元素都是簡單數據類型,所以相當於定義了兩個簡單數組;

DECLARE
TYPE ename_table_type IS TABLE OF
employees.last_name%TYPE
INDEX BY BINARY_INTEGER;
TYPE hiredate_table_type IS TABLE OF DATE
INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
hiredate_table hiredate_table_type;
BEGIN
ename_table(1) := 'CAMERON';
hiredate_table(8) := SYSDATE + 7;
IF ename_table.EXISTS(1) THEN
INSERT INTO ...
...
END;
/

備註:對PLSQL 內存表中某個元素的訪問類似於數組,可以使用下表,因爲BINARY_INTEGER 這種數據類型
在 的值在-2147483647 ... 2147483647 範圍內,所以下表也可以在這個範圍內。

 

PLSQL中的遊標

遊標概論:遊標是一個私有的SQL 工作區域,Oracle 數據庫中有兩種遊標,分別是隱式遊標和顯式遊標,
隱 式 遊標不易被用戶和程序員察覺和意識到,實際上Oracle 服務器使用隱式遊標來解析和執行我們提交的SQL
語句;而顯式遊標是程序員在程序中顯式聲明的;通常我們說的遊標均指顯式遊標。

 

隱式遊標的幾個有用屬性:

顯式遊標:對於返回多行結果的SQL 語句的返回結果,可使用顯式遊標獨立的處理器中每一行的數據。

 

顯式遊標的相關函數可以做到:

1 、一行一行的處理返回的數據。
2 、保持當前處理行的一個跟蹤,像一個指針一樣指示當前的處理的記錄。
3 、允許程序員在PLSQL 塊中人爲的控制遊標的開啓、關閉、上下移動;

 

在程序中對顯式遊標控制的一般過程:

 

如果你覺得像前面那個例子那樣對一個遊標的遍歷很麻煩的話,可以考慮使用For 循環,For 循環省去了遊標的
聲明、打開、提取、測試、關閉等語句,對程序員來說很方便,語法如下:

FOR record_name IN cursor_name LOOP
statement1;
statement2;
. . .
END LOOP;

遊標能否帶有參數?答案是肯定的:

CURSOR cursor_name
[(parameter_name datatype, ...)]
IS
select_statement;

 

FOR UPDATE NOWAIT 語句:

有的時候我們打開一個遊標是爲了更新或者刪除一些記錄,這種情況下我們希望
用 在打開遊標的時候即鎖定相關記錄,應該使用for update nowait 語句,倘若鎖定失敗我們就停止不再繼續,以免
出現長時間等待資源的死鎖情況。

SELECT ...
FROM ...
FOR UPDATE [OF column_reference][NOWAIT];

WHERE CURRENT OF cursor :

我們經常要逐條處理遊標中的每一條記錄,在循環體內做Update 或者 Delete
有 時需要有Where 指向遊標的當前記錄,的 有沒有簡單一點的的Where 條件寫法呢?

答案是肯定的,就是。。。

DECLARE
CURSOR sal_cursor IS
SELECT e.department_id, employee_id, last_name, salary
FROM employees e, departments d
WHERE d.department_id = e.department_id
and d.department_id = 60
FOR UPDATE OF salary NOWAIT;
BEGIN
FOR emp_record IN sal_cursor
LOOP
IF emp_record.salary < 5000 THEN
UPDATE employees
SET salary = emp_record.salary * 1.10
WHERE CURRENT OF sal_cursor;
END IF;
END LOOP;
END;
/

 

PLSQL中的例外處理


PLSQL 中的例外一般有兩種:
1 、Oracle 內部錯誤拋出的例外:這又分爲預定義例外(有錯誤號+ 常量定義)和 和 非預定義例外
(僅有錯誤號,無常量定義)
2 、程序員顯式的拋出的例外

 

PLSQL 中的 例外捕獲和傳遞:與其他語言類似,如果例外在當前塊中被處理,則到此爲止,否則會被傳遞到
外層(外層BLOCK 或者 外層調用者函數)

PLSQL 中的例外處理一般語法:

 

處理預定義的例外:有些常見例外,Oracle 都已經預定義好了,使用時無需預先聲明,比如:
NO_DATA_FOUND 和 和 TOO_MANY_ROWS 是最常見的例外,大多數Block 中都建議對這兩種例外
有處理; 完整的預定義例外的列表,

請參考:PL/SQL User’s Guide and Reference, “Error Handling.” (百度搜索,下載點很多)

 

OTHERS 的處理:

Others 表明我們程序員未能預計到這種錯誤,所以全部歸入到others 裏面去了,單發生這種的情況是,我們還是希望瞭解當時發生的Oracle 錯誤號和相關描述信息,怎樣才能取到呢?Oracle 提供了兩個內置函數SQLCODE 和 和 SQLERRM 分別用來返回Oracle 錯誤號和錯誤描述

處理非預定義的Oracle 錯誤:

此類錯誤屬於Oracle 錯誤,有編號,但無錯誤名稱定義,使用時需要先聲明,並進行錯誤初始化:

 

Oracle 內部錯誤號很多,想了解全部的Ora 錯誤號,請參考:http://www.ora-code.com/

 

處理用戶自定義的錯誤:

這種錯誤一般是程序員根據具體的業務邏輯定義的應用類錯誤,需要先聲明後使用:
定義和處理過程如下:

 

 

RAISE_APPLICATION_ERROR() 函數:對於用戶自定義的業務錯誤,如果覺得先定義再使用很麻煩,那麼也可以簡單的使用raise_application_error() 來簡化處理。它可以無需預先定義錯誤,而在需要拋出錯誤的地方直接使用此函數拋出例外,例外可以包含用戶自定義的錯誤嗎和錯誤描述;

 

PLSQL中的存儲過程和函數:

語法:

CREATE [OR REPLACE] PROCEDURE procedure_name
[(parameter1 [mode1] datatype1,
parameter2 [mode2] datatype2,
. . .)]
IS|AS
PL/SQL Block;

 

自己去深入瞭解吧,這裏是重點!!!說不清

 

 

 

今日作業:重點存儲過程!!

-- 學生表:學號、姓名、性別、年齡、班級 
select * from t2_student;

create table t2_student(
sno varchar2(11) primary key,
sname varchar2(20) not null,
sex varchar2(3),
age number(3),
classid varchar2(5),
classname varchar2(20),
constraint c2_1 check(sex in ('男','女'))
);

-- 成績表:學號、課程、成績 
select * from t2_grade;

create table t2_grade(
sno varchar2(11),
cno varchar2(5),
cname varchar2(20),
grade number,
constraint c2_2 check(grade >=0 and grade <=100)
);


insert into t2_student values('s001','張三','男',15,'c001','18班');
insert into t2_student values('s002','李華','女',15,'c001','18班');

insert into t2_student values('s003','李斯','男',16,'c002','19班');
insert into t2_student values('s004','王武','男',16,'c002','19班');
insert into t2_student values('s005','趙柳','女',16,'c002','19班');
insert into t2_student values('s006','孫琪','女',17,'c002','19班');


insert into t2_grade values('s001','c01','語文',90);
insert into t2_grade values('s001','c02','數學',80);

insert into t2_grade values('s002','c01','語文',70);
insert into t2_grade values('s002','c02','數學',90);


insert into t2_grade values('s003','c02','數學',80);
insert into t2_grade values('s004','c02','數學',91);
insert into t2_grade values('s005','c02','數學',92);
insert into t2_grade values('s006','c02','數學',93);


-- 以下都是存儲過程的練習,要求使用存儲過程操作 
-- 1、插入3條數據到學生表 
select * from t2_student;

create or replace procedure proc_insert_student
       (v_age in t2_student.age%TYPE) 
is
begin 
insert into t2_student values('s007','老八','男',v_age,'c003','20班');
insert into t2_student values('s008','老九','女',v_age,'c003','20班');
insert into t2_student values('s009','老十','男',v_age,'c003','20班');
commit;
end proc_insert_student;


begin 
  cheirmin.proc_insert_student(18);
end;

-- 2、打印所有18歲的學生 
--使用存儲過程加遊標
create or replace procedure proc_select_age_student 
       (v_age t2_student.age%TYPE)
is 
       cursor stu_cursor1 is 
              select sname,age from t2_student where age = v_age;
       c_sname t2_student.sname%TYPE :='';
       c_age t2_student.age%TYPE :=0;
begin 
    open stu_cursor1;
    loop
      fetch stu_cursor1 into c_sname,c_age;
      exit when stu_cursor1%notfound;
      dbms_output.put_line(c_sname||' - '||c_age);
    end loop;
    close stu_cursor1;
end proc_select_age_student;

--調用存儲過程
begin 
  cheirmin.proc_select_age_student(18);
end;

--只使用遊標
declare
  v_age t2_student.age%TYPE := 0;
  v_sname t2_student.sname%TYPE :='';
   cursor stu_cursor1 is
          select sname,age from t2_student where age = 18;
begin 
    open stu_cursor1;
    loop
      fetch stu_cursor1 into v_sname,v_age;
      exit when stu_cursor1%rowcount > 10 or stu_cursor1%notfound;
      dbms_output.put_line(v_sname||' - '||v_age);
    end loop;
    close stu_cursor1;
end;  


-- 3、更新“張三”的年齡爲20歲,返回更新後的數據 
select * from t2_student where sname = '張三';


create or replace procedure proc_update_age 
       (v_age  in  t2_student.age%TYPE,
        c_name out t2_student.sname%TYPE,
        c_age  out t2_student.age%TYPE)
is
begin 
update t2_student set age =  v_age where sname = '張三';
commit;
select sname,age into c_name,c_age from t2_student where sname = '張三';
end proc_update_age;

--執行代碼塊測試上述存儲過程;成立
declare
    v_name varchar2(20);
    v_age number(3);
begin 
    cheirmin.proc_update_age(20,v_name,v_age);
    dbms_output.put_line(v_name||' - '||v_age);
end;


-- 4、將“張三”的年齡、性別、班級數據賦值給“李斯” 
select * from t2_student where sname = '張三';
select * from t2_student where sname = '李斯';

create or replace procedure proc_select_and_update 
as   
       v_age t2_student.age%TYPE;
       v_sex t2_student.sex%TYPE;
       v_classid t2_student.classid%TYPE;
       v_classname t2_student.classname%TYPE;
begin 
  select age,sex,classid,classname  
  into v_age,v_sex,v_classid,v_classname 
  from t2_student where sname = '張三';--查
  
  update t2_student 
  set age = v_age,sex = v_sex,classid = v_classid,classname = v_classname 
  where sname = '李斯';--賦值
  
end proc_select_and_update;

--執行代碼塊測試上述存儲過程;成立
begin 
    cheirmin.proc_select_and_update;
end;


-- 5、將“19班”學生的所有成績全部在原有基礎上加10分 
select * from t2_student;
select * from t2_grade;

update t2_grade set grade = grade+10 where sno in(
select sno from t2_student where classname = '19班');


create or replace procedure proc_update_grade 
is 
       cursor p_cursor2 is 
              select sno from t2_student where classname = '19班';
       c_sno t2_student.sno%TYPE :=' ';
begin 
  open p_cursor2;
  loop
    fetch p_cursor2 into c_sno;
    exit when p_cursor2%notfound;
    update t2_grade set 
    grade = (case when grade <90 then (grade +10) else 100 end) 
    where sno = c_sno;
  end loop;
  close p_cursor2;
end proc_update_grade;

--執行代碼塊測試上述存儲過程;成立
begin 
    cheirmin.proc_update_grade;
end;



-- 6、查詢“張三”的語文課成績(一個入參) 
select * from t2_student;
select * from t2_grade;

create or replace procedure proc_select_grade
       (v_cname  in  t2_grade.cname%TYPE,
        c_grade out t2_grade.grade%TYPE)
is
begin 
        select grade into c_grade 
        from t2_grade where sno =   
        (select sno from t2_student where sname = '張三')
        and cname = v_cname;
end proc_select_grade;

--執行代碼塊測試上述存儲過程;成立
declare
    v_grade t2_grade.cname%TYPE;
begin 
    cheirmin.proc_select_grade('語文',v_grade);
    dbms_output.put_line(v_grade);
end;


-- 7、刪除“張三”的數學成績 

create or replace procedure proc_delete_grade
is
begin 
        delete from t2_grade where sno =   
        (select sno from t2_student where sname = '張三')
        and cname = '數學';
end proc_delete_grade;

begin 
    cheirmin.proc_delete_grade;
end;




 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章