99
14 14 PL/SQL PL/SQL 第第第第 第第第第 第第 一、 第第 一、 DECLARE DECLARE N N CHAR(8) CHAR(8) ; ; SAL SAL NUMBER(5) NUMBER(5) ; ; I I NUMBER(2) NUMBER(2) ; ; BEGIN BEGIN SELECT SALARY SELECT SALARY INTO SAL INTO SAL FROM EMPLOYEES FROM EMPLOYEES WHERE EMPLOYEE_ID='201' WHERE EMPLOYEE_ID='201' ; ; IF SAL <10000 THEN IF SAL <10000 THEN DBMS_OUTPUT.PUT_LINE(TO_CHAR(SAL)||' DBMS_OUTPUT.PUT_LINE(TO_CHAR(SAL)||' 第第 第第 ') ') ; ; ELSE ELSE DBMS_OUTPUT.PUT_LINE(TO_CHAR(SAL)||' DBMS_OUTPUT.PUT_LINE(TO_CHAR(SAL)||' 第第第 第第第 ') ') ; ; END IF END IF ; ; END END ; ;

第14章 PL/SQL 语言基础

  • Upload
    nika

  • View
    135

  • Download
    0

Embed Size (px)

DESCRIPTION

第14章 PL/SQL 语言基础. 一、例子 DECLARE N CHAR(8) ; SAL NUMBER(5) ; I NUMBER(2) ; BEGIN SELECT SALARY INTO SAL FROM EMPLOYEES WHERE EMPLOYEE_ID='201' ; IF SAL

Citation preview

Page 1: 第14章  PL/SQL 语言基础

第第 1414 章 章 PL/SQLPL/SQL 语言基础语言基础一、例子一、例子DECLAREDECLARE NN CHAR(8) CHAR(8);; SALSAL NUMBER(5) NUMBER(5);; II NUMBER(2) NUMBER(2);;BEGINBEGIN SELECT SALARY SELECT SALARY INTO SALINTO SAL FROM EMPLOYEES FROM EMPLOYEES WHERE EMPLOYEE_ID='201'WHERE EMPLOYEE_ID='201';; IF SAL <10000 THENIF SAL <10000 THEN DBMS_OUTPUT.PUT_LINE(TO_CHAR(SAL)||' DBMS_OUTPUT.PUT_LINE(TO_CHAR(SAL)||' 太少太少 ')');; ELSEELSE DBMS_OUTPUT.PUT_LINE(TO_CHAR(SAL)||' DBMS_OUTPUT.PUT_LINE(TO_CHAR(SAL)||' 还可以还可以 ')');; END IFEND IF;;ENDEND;;

Page 2: 第14章  PL/SQL 语言基础

二、二、 PL/SQLPL/SQL 简述简述 1. 1. PL/SQLPL/SQL 块及程序块及程序 PL/SQLPL/SQL 是一种过程化编程语言。用是一种过程化编程语言。用 PL/SQLPL/SQL 定定义块可将多个义块可将多个 SQLSQL 编制成程序(程序过程、函数编制成程序(程序过程、函数触发器等)。程序是由若干触发器等)。程序是由若干 PL/SQLPL/SQL 块组成。块组成。 2. PL/SQL2. PL/SQL 块结构与用途块结构与用途 PL/SQLPL/SQL 块由三部分组成:块由三部分组成:定义部分定义部分:定义所处理的变量、常量、游标等。:定义所处理的变量、常量、游标等。可执行部分可执行部分:: SQLSQL 语句及控制结构的语句及控制结构的 PL/SQLPL/SQL 语句语句异常处理部分异常处理部分:对执行过程中的错误进行处理。:对执行过程中的错误进行处理。块可以嵌套。块可以嵌套。

Page 3: 第14章  PL/SQL 语言基础

块结构:块结构:[[DECLAREDECLARE 说明部分 说明部分 ]] BEGINBEGIN 语句语句 ((SQLSQL 或或 PL/SQLPL/SQL 语句)语句) [[EXCEPTIONEXCEPTION 错误处理程序 错误处理程序 ]] END END 3. 3. PL/SQLPL/SQL 程序分类程序分类 由基本由基本 PL/SQLPL/SQL 块组成块组成 PL/SQLPL/SQL 程序。程序有:程序。程序有: 无名块无名块:它嵌入在某个应用中的:它嵌入在某个应用中的 PL/SQLPL/SQL 块。块。 存储过程或函数存储过程或函数:命名了的:命名了的 PL/SQLPL/SQL 块,可以块,可以

带带

Page 4: 第14章  PL/SQL 语言基础

参数,并重复调用,是数据库对象。参数,并重复调用,是数据库对象。 包包:是命名:是命名 PL/SQLPL/SQL 块,由一组相关的过程、函块,由一组相关的过程、函数和标识符组成。是数据库对象。数和标识符组成。是数据库对象。 触发器触发器 :: 与表相关联的存储过程。一表最多与表相关联的存储过程。一表最多 1212 个。个。

4. 4. PL/SQLPL/SQL 程序运行环境程序运行环境 可以有多个:可以有多个: SQL Plus Worksheet,SQL PLUSSQL Plus Worksheet,SQL PLUS

等。 在等。 在 SQL PLUSSQL PLUS 环境中,第一句是环境中,第一句是 DECLAREDECLARE 或或BEGINBEGIN 就识别为是就识别为是 PL/SQLPL/SQL 程序。它只能以程序。它只能以““ /”/” 表表示程序结束。示程序结束。

Page 5: 第14章  PL/SQL 语言基础

三、三、 PL/SQLPL/SQL 基础基础1.1. 标识符标识符 标识符是用户定义的符号串,用来命名变量、常标识符是用户定义的符号串,用来命名变量、常量、过程等。量、过程等。 标识符以字母开头,后跟数字标识符以字母开头,后跟数字 (0-9)(0-9) 或特殊字符或特殊字符 $$ 、、## 和和 __ 。长度不超过。长度不超过 3030 ,不能是,不能是 PL/SQLPL/SQL 的保留字,的保留字,不能有空格。不能有空格。 例例 11 :合法标识符::合法标识符: A34A34 、、 BB#BB# ,, D_123DFD_123DF 不合法标识符:不合法标识符: 55A$A$ 、、 #ABC#ABC 、、 ENDEND 。。2. 2. 变量及变量说明变量及变量说明 变量变量是表示要处理数据项的名称。是表示要处理数据项的名称。变量名变量名用标识用标识符来表示。符来表示。 变量在使用之前必须用变量在使用之前必须用 DECLAREDECLARE 进行说明。进行说明。

Page 6: 第14章  PL/SQL 语言基础

变量说明:变量说明: 变量名 变量名 [[CONSTANT] CONSTANT] 类型类型 [NOT NULL[NOT NULL][:=][:= 值值 ][DEFAULT SQL][DEFAULT SQL 表达表达

式式 ]] ;;例例 11: : DECLAREDECLARE aa char(5) aa char(5) not null:=‘TEST’; not null:=‘TEST’; bb number(3) default 5;bb number(3) default 5; cc char(4):='THIS'cc char(4):='THIS';; dd constant char(4) :=‘SWJ’; --dd constant char(4) :=‘SWJ’; -- 不能赋值不能赋值 beginbeginDBMS_OUTPUT.PUT_LINE(aa||' '||to_char(bb)||' '||cc||' '||DD);DBMS_OUTPUT.PUT_LINE(aa||' '||to_char(bb)||' '||cc||' '||DD);

endend;;     说明说明:非空时要有初始值:非空时要有初始值 ,,NOT NULLNOT NULL 在前,缺省在前,缺省值在后;每个变量说明占一行,且以值在后;每个变量说明占一行,且以分号“;”分号“;”结结束。变量说明要在束。变量说明要在 DECLAREDECLARE 以后,以后, BEGINBEGIN 之前。之前。

Page 7: 第14章  PL/SQL 语言基础

3.3. 变量或常量类型变量或常量类型数值型:数值型: NUMBER(p,s),INTEGER,FLOAT,DECNUMBER(p,s),INTEGER,FLOAT,DEC

字符型:字符型: CHAR(n),VARCHAR2(n),RAW(n)CHAR(n),VARCHAR2(n),RAW(n)

日期型:日期型: DATEDATE

布尔型:布尔型: BOOLEAN(TRUEBOOLEAN(TRUE 或或 FALSE)FALSE)

大数据类型:大数据类型: BFILE,BLOB,CLOB,NCLOBBFILE,BLOB,CLOB,NCLOB

4. 4. 数据类型转换数据类型转换显示转换显示转换 : : TO_CHAR(),TO_NUMBER(), RAWTOHEX(),TO_CHAR(),TO_NUMBER(), RAWTOHEX(),,HEXTORAW(),ROWIDTOCHAR(),TO_DATE(),HEXTORAW(),ROWIDTOCHAR(),TO_DATE()

Page 8: 第14章  PL/SQL 语言基础

5. 5. 函数函数

Page 9: 第14章  PL/SQL 语言基础

6. 6. 表达式表达式  表达式表达式是由变量、常量、列名、函数和运算符是由变量、常量、列名、函数和运算符结合的有意义式子。结合的有意义式子。数值表达式数值表达式:数值运算符、变量、常量、函数等:数值运算符、变量、常量、函数等数值运算符:数值运算符: ++ 、、 -- 、*、、*、 // 、、 **** 、、 ()()例例 2: 2: DECLAREDECLARE A INT :=4;A INT :=4; B FLOAT:=4.324; B FLOAT:=4.324; X FLOAT;X FLOAT; BEGINBEGIN X:= X:= SIN(3)*10+2**8-A*10*(10-B**2)SIN(3)*10+2**8-A*10*(10-B**2);; DBMS_OUTPUT.PUT_LINE(DBMS_OUTPUT.PUT_LINE(TO_CHAR(X)TO_CHAR(X)); ); ENDEND;;

Page 10: 第14章  PL/SQL 语言基础

字符表达式:字符表达式:字符运算符字符运算符 : ||(: ||( 合并合并 ))

关系表达式关系表达式 :: 关系表达式的结果是关系表达式的结果是 TRUETRUE 和和FALSEFALSE

关系运算符关系运算符 : <> != < > <= >= = : <> != < > <= >= = LIKE IN LIKE IN BETWEEN…AND…BETWEEN…AND… << 表达式 表达式 >>    << 关系运算符关系运算符 > <> < 表达式表达式 >>

例例 33: : ABC > ‘123ABC > ‘123’ ’ 123<>345 123<>345 ‘ ‘THIS’ LIKE ‘T%’THIS’ LIKE ‘T%’

      X BETWEEN 10 AND 20 X BETWEEN 10 AND 20 ‘ ‘A’ IN (‘SS’,’DD’,’AD’) FALSE A’ IN (‘SS’,’DD’,’AD’) FALSE SIN(X)+10 > A**2+BSIN(X)+10 > A**2+B

Page 11: 第14章  PL/SQL 语言基础

逻辑表达式逻辑表达式逻辑运算符:逻辑运算符: NOT AND ORNOT AND OR   << 关系表达式关系表达式 > <> < 逻辑表达式逻辑表达式 > <> < 关系表达式关系表达式 >>例例 44: : NOT (A >10 AND B<10)NOT (A >10 AND B<10) A+10>100 AND CCC LIKE ‘C%’A+10>100 AND CCC LIKE ‘C%’例例 55: : DECLAREDECLARE A INT :=4;A INT :=4; B FLOAT:=4.324; B FLOAT:=4.324; X FLOAT;X FLOAT; C BOOLEAN;C BOOLEAN; BEGINBEGIN X:= X:= SIN(3)*10+2**8-A*10*(10-B**2);SIN(3)*10+2**8-A*10*(10-B**2); C:=C:='A' IN ('SS','DD','AD');'A' IN ('SS','DD','AD'); IF IF C OR A<BC OR A<B THEN THEN DBMS_OUTPUT.PUT_LINE(TO_CHAR(X)); DBMS_OUTPUT.PUT_LINE(TO_CHAR(X)); END IF;END IF; ENDEND;;

Page 12: 第14章  PL/SQL 语言基础

7. 7. 变量赋值变量赋值  变量名变量名:: == 与变量同类型的表达式;与变量同类型的表达式;例例 66: : DECLAREDECLARE C1 CHAR(34) ; --C1 CHAR(34) ; -- 赋给赋给 C1C1 的字符串不能大于的字符串不能大于 3434

N1 NUMBER(3);N1 NUMBER(3); N2 NUMBER(2);N2 NUMBER(2); B1 BOOLEAN;B1 BOOLEAN; BEGINBEGIN N1:=10;N1:=10; N2:=SIN(N1)**2+20.30;N2:=SIN(N1)**2+20.30; C1:=TO_CHAR(N2)||’ TEST’;C1:=TO_CHAR(N2)||’ TEST’; B1:= C1 LIKE ‘%T’;B1:= C1 LIKE ‘%T’; ENDEND;;

Page 13: 第14章  PL/SQL 语言基础

8. 8. 注释行注释行单行注释:在一行的任何位置以“单行注释:在一行的任何位置以“ ---- 字符串字符串””多行注释:多行注释: /* /* 注释内容 注释内容 */*/

例例 77::DECLAREDECLARE C1 CHAR(34); C1 CHAR(34); ---- 字符变量,长度不超过字符变量,长度不超过 3434

      N1 NUMBER(3); --N1 NUMBER(3); -- 数字型变量数字型变量 BEGINBEGIN /* /* 赋值语句范例:赋值语句范例:     变量类型要与表达式类型一致      变量类型要与表达式类型一致 */*/ N1:=10;N1:=10; C1:=TO_CHAR(N1)||' TEST';C1:=TO_CHAR(N1)||' TEST'; END;END;

Page 14: 第14章  PL/SQL 语言基础

9. 9. PL/SQLPL/SQL 中的语句中的语句 PL/SQLPL/SQL 块中每一行一条语句,并且必须以分号块中每一行一条语句,并且必须以分号““ ;”;”结束。结束。 变量或常量说明语句、 变量赋值语句、变量或常量说明语句、 变量赋值语句、 CASECASE

语语句和句和 IFIF 语句、 各种循环语句、数据处理语句语句、 各种循环语句、数据处理语句

SIDUSIDU 、、事务处理语句、 事务处理语句、 DBMS_OUTPUT.PUT_LINE(DBMS_OUTPUT.PUT_LINE( 字字符串符串 )) 、 游标语句等。、 游标语句等。COMMITCOMMIT 、、 ROLLBACKROLLBACKEXECUTE IMMEDIATE EXECUTE IMMEDIATE 动态串动态串SELECT…SELECT…INTO INTO 变量名表变量名表 || 记录名记录名 FROM…FROM…

每个块由若干语句组成。若干块组成程序。每个块由若干语句组成。若干块组成程序。

Page 15: 第14章  PL/SQL 语言基础

四、四、 PL/SQLPL/SQL 控制结构控制结构 三种程序结构:顺序、选择和循环三种程序结构:顺序、选择和循环1.1. 顺序结构顺序结构顺序结构是指执行过程按所写程序的顺序执行。顺序结构是指执行过程按所写程序的顺序执行。例例 11 :: DECLAREDECLARE VV CHAR(20);VV CHAR(20); SAL NUMBER(4);SAL NUMBER(4); BEGINBEGIN SELECT LAST_NAME SELECT LAST_NAME INTO VVINTO VV FROM FROM EMPLOYEES WHERE EMPLOYEES WHERE

EMPLOYEE_ID=201;EMPLOYEE_ID=201; DBMS_OUTPUT.PUT_LINE(VV);DBMS_OUTPUT.PUT_LINE(VV); SAL:=10;SAL:=10; END;END;

Page 16: 第14章  PL/SQL 语言基础

例例 22 :: DECLAREDECLARE

JIDJID VARCHAR2(10):='AD_VP'; VARCHAR2(10):='AD_VP';

JTIT CHAR(30);JTIT CHAR(30);

BEGINBEGIN

SELECT JOB_TITLE INTO JTITSELECT JOB_TITLE INTO JTIT

FROM JOBS WHERE JOB_ID=FROM JOBS WHERE JOB_ID=JIDJID;;

DBMS_OUTPUT.PUT_LINE(JTIT);DBMS_OUTPUT.PUT_LINE(JTIT);

END;END;

说明说明:: JIDJID 的类型与的类型与 JOB_IDJOB_ID 的类型要完全一致,的类型要完全一致,且长度要一样。改为且长度要一样。改为 JID CHAR(10)JID CHAR(10) 将出错。将出错。可改为:可改为: JID JOBS.JOB_ID%TYPE:=‘AD_VP’;JID JOBS.JOB_ID%TYPE:=‘AD_VP’;

Page 17: 第14章  PL/SQL 语言基础

2. 2. IFIF 选择结构选择结构

条件

语句1

语句2

IF IF 条件条件 THENTHEN

语句序列;语句序列;ENDEND IF;IF;

““ 条件”为逻辑表达式或关条件”为逻辑表达式或关系表达式,“条件”为系表达式,“条件”为TRUETRUE 时执行“语句序列”,时执行“语句序列”,为为 FALSEFALSE 时执行时执行 END IFEND IF后面的语句。后面的语句。IF IF 条件条件 THENTHEN

语句序列语句序列 1 1 ELSEELSE 语句序列语句序列 22END IF;END IF;

Page 18: 第14章  PL/SQL 语言基础

IF IF 条件条件 11 THEN THEN 语句序列语句序列 11ELSIF ELSIF 条件条件 2 2 THENTHEN 语句序列语句序列 22ELSEELSE 语句序列语句序列 33END IF;END IF;例例 1: 1: DECLAREDECLARE N1 NUMBER:=11;N1 NUMBER:=11; N2 NUMBER;N2 NUMBER; BEGINBEGIN IFIF N1>10 THEN N1>10 THEN N2:=N1+10; N2:=N1+10;

DBMS_OUTPUT.PUT_LINE(TO_CHAR(N2));DBMS_OUTPUT.PUT_LINE(TO_CHAR(N2)); END IF;END IF; END;END;

Page 19: 第14章  PL/SQL 语言基础

例例 22 ::嵌套选择结构嵌套选择结构DECLAREDECLARE N1 NUMBER:=11;N1 NUMBER:=11; N2 NUMBER DEFAULT 10;N2 NUMBER DEFAULT 10; BEGINBEGIN IF N1>10 THENIF N1>10 THEN IF N2<N1 THENIF N2<N1 THEN N2:=N1+10;N2:=N1+10;

DBMS_OUTPUT.PUT_LINE(TO_CHAR(N2));DBMS_OUTPUT.PUT_LINE(TO_CHAR(N2)); END IFEND IF;; END IF;END IF; END;END;说明说明:嵌套必须是完全嵌套:嵌套必须是完全嵌套 ,, 可以是任何选择结构可以是任何选择结构IF_END IFIF_END IF 、、 IF_ELSE_END IF IF_ELSE_END IF 等。 等。

Page 20: 第14章  PL/SQL 语言基础

例例 33 :: IF…THEN…ELSEIF…THEN…ELSE 结构结构DECLAREDECLARE N1 NUMBER:=9;N1 NUMBER:=9; N2 NUMBER:=19;N2 NUMBER:=19;BEGINBEGIN IFIF N1>10 N1>10 THENTHEN N2:=N2+10;N2:=N2+10; ELSEELSE N2:=N1*N1;N2:=N1*N1; END IFEND IF;; DBMS_OUTPUT.PUT_LINE(TO_CHAR(n2));DBMS_OUTPUT.PUT_LINE(TO_CHAR(n2));

END;END;

Page 21: 第14章  PL/SQL 语言基础

例例 44: : IF…THEN…IF…THEN…ELSIFELSIF…END IF…END IF 结构结构DECLAREDECLARE N1 NUMBER:=10;N1 NUMBER:=10; N2 NUMBER:=20;N2 NUMBER:=20; CC CHAR(20);CC CHAR(20); C2 DATE:=C2 DATE:=TO_DATE('1999-1-1','YYYY-MM-DD');TO_DATE('1999-1-1','YYYY-MM-DD');BEGINBEGIN DBMS_OUTPUT.PUT_LINE(TO_CHAR(C2));DBMS_OUTPUT.PUT_LINE(TO_CHAR(C2)); IFIF N1>10 N1>10 THENTHEN N2:=N1+10;N2:=N1+10; ELSIFELSIF N1 BETWEEN 7 AND 12 N1 BETWEEN 7 AND 12 THENTHEN N2:=SQRT(N1)*2;N2:=SQRT(N1)*2; ELSIFELSIF C2>=DATE'1998-1-1' C2>=DATE'1998-1-1' THENTHEN CC:=TO_CHAR(SYSDATE);CC:=TO_CHAR(SYSDATE); ELSEELSE CC:='NO RESULT';CC:='NO RESULT'; END IFEND IF;; DBMS_OUTPUT.PUT_LINE(CC||' '||TO_CHAR(N2));DBMS_OUTPUT.PUT_LINE(CC||' '||TO_CHAR(N2));END;END;

Page 22: 第14章  PL/SQL 语言基础

3. 3. CASECASE 选择结构选择结构CASE CASE 变量变量WHEN WHEN 表达式表达式 1 1 THEN THEN

语句序列语句序列 11;;

WHEN WHEN 表达式表达式 2 THEN2 THEN

语句序列语句序列 2;2;

…………

WHEN WHEN 表达式表达式 N N THENTHEN

语句序列语句序列 N;N;

[ELSE [ELSE 语句序列语句序列 N+1;]N+1;]

END CASEEND CASE

说明 :

1. 当“变量”的值与当“变量”的值与某个表达式值相同时,某个表达式值相同时,将执行相应的语句序列将执行相应的语句序列

2. 当变量与所有表达当变量与所有表达式不等时执行序列式不等时执行序列 N+1N+1

3.3. 语句序列语句序列 11 到语句序到语句序列列 N+1N+1 中只能执行一中只能执行一个语句序列。个语句序列。

Page 23: 第14章  PL/SQL 语言基础

例例 11 :: DECLAREDECLARE C1 CHAR(1):='F';C1 CHAR(1):='F'; N1 NUMBER:=2;N1 NUMBER:=2; N2 NUMBER:=35;N2 NUMBER:=35; NC NUMBER;NC NUMBER;BEGINBEGIN NC:=ASCII(C1);NC:=ASCII(C1); CASECASE NC NC WHENWHEN N2*N2 N2*N2 THENTHEN N1:=N2*N2;N1:=N2*N2; DBMS_OUTPUT.PUT_LINE('N1='||TO_CHAR(N1));DBMS_OUTPUT.PUT_LINE('N1='||TO_CHAR(N1)); WHENWHEN N2+N2 THEN N2+N2 THEN N1:=N2+N2;N1:=N2+N2; DBMS_OUTPUT.PUT_LINE('N1='||TO_CHAR(N1));DBMS_OUTPUT.PUT_LINE('N1='||TO_CHAR(N1)); ELSEELSE DBMS_OUTPUT.PUT_LINE('N1='||TO_CHAR(N1));DBMS_OUTPUT.PUT_LINE('N1='||TO_CHAR(N1)); DBMS_OUTPUT.PUT_LINE('NC='||TO_CHAR(NC)); DBMS_OUTPUT.PUT_LINE('NC='||TO_CHAR(NC)); END CASEEND CASE; END;; END;

Page 24: 第14章  PL/SQL 语言基础

4. 4. 循环结构循环结构循环结构是指按照指定的逻辑条件循环执行一组循环结构是指按照指定的逻辑条件循环执行一组命令。有三种循环:命令。有三种循环: LOOP-EXIT-END;LOOP-LOOP-EXIT-END;LOOP-

EXIT-WHEN-END;WHILE-LOOP-ENDEXIT-WHEN-END;WHILE-LOOP-END 和和 FOR-FOR-

IN-LOOP-ENDIN-LOOP-END 。。

条件

语句序列

当条件为真时,执行语句当条件为真时,执行语句序列,直到条件为假。序列,直到条件为假。

条件条件是任何合法的逻辑表是任何合法的逻辑表达式或关系表达式。达式或关系表达式。

Page 25: 第14章  PL/SQL 语言基础

4.1 LOOP-EXIT-END4.1 LOOP-EXIT-END 循环循环 LOOPLOOP

语句序列语句序列 [[EXIT]EXIT]

END LOOPEND LOOP

说明说明:执行:执行 EXITEXIT 时从循环时从循环中退出,在条件语句中执中退出,在条件语句中执行行 EXITEXIT 。。该循环中,必须该循环中,必须有有 EXIT,EXIT, 否则就会成为“死否则就会成为“死循环”。循环”。 EXITEXIT 只能在循环。只能在循环。

例 1 :计算 1+2+3…+100DECLARE I INT :=1; S INT:=0;BEGIN LOOP S:=S+I; IF I=100 THEN EXIT; END IF; I:=I+1; END LOOP;DBMS_OUTPUT.PUT_LINE(TO_CHAR(S)); END;

Page 26: 第14章  PL/SQL 语言基础

4.2 LOOP-EXIT WHEN-END4.2 LOOP-EXIT WHEN-END 循环循环 LOOPLOOP 语句序列语句序列 EXIT WITH EXIT WITH 条件 条件 ---- 等价等价 IF IF 条件 条件 THEN EXITTHEN EXIT ,,可用在其它可用在其它

循环循环

END LOOPEND LOOP例例 22 :计算:计算 1010 !!DECLARE I INT :=1; S INT:=1;BEGIN LOOP S:=S*I; EXIT WHEN I=10; I:=I+1; END LOOP; DBMS_OUTPUT.PUT_LINE(TO_CHAR(S)); END;

Page 27: 第14章  PL/SQL 语言基础

4. 3 4. 3 WHILE-LOOP-ENDWHILE-LOOP-END 循环循环WHILE WHILE 条件 条件 LOOP LOOP 每次循环前计算条每次循环前计算条

语句序列; 语句序列; 件,为件,为 TRUETRUE ,,执执 END LOOPEND LOOP ; ; 行语句,否则行语句,否则

不。不。例例 33 :计算:计算 s=1*2+2*3+…+N*(N+1),s=1*2+2*3+…+N*(N+1), 当当 N=50N=50 的值。的值。DECLARE I INT :=1; S INT:=0;BEGIN WHILE I<=50 LOOP S:=S+I*(I+1); I:=I+1; END LOOP;DBMS_OUTPUT.PUT_LINE(TO_CHAR(S)); END;

Page 28: 第14章  PL/SQL 语言基础

例例 44 :在:在 WHILEWHILE 循环中使用循环中使用 EXITEXIT 或或 EXIT WHENEXIT WHEN计算 S=1*2*3+2*3*4+…+N*(N+1)*(N+2); 当 N=40DECLARE I INT :=1; S INT:=0;BEGIN WHILE TRUE LOOP S:=S+I*(I+1)*(I+2); EXIT WHEN I=40; I:=I+1; END LOOP;DBMS_OUTPUT.PUT_LINE(TO_CHAR(S)); END; 说明说明:: EXITEXIT 和和 EXIT WHENEXIT WHEN 可用在任何循环内,可用在任何循环内,且只能在循环内。且只能在循环内。

Page 29: 第14章  PL/SQL 语言基础

4.4 4.4 FOR-IN-LOOP-ENDFOR-IN-LOOP-END 循环循环FOR FOR 循环变量 循环变量 IN [REVERSE]IN [REVERSE] 下界下界 .... 上界 上界 LOOPLOOP 语句序列;语句序列;END LOOPEND LOOP ;;

说明说明::循环变量被隐式说明为循环变量被隐式说明为 BINARY-INTEGERBINARY-INTEGER ,,也也

可显式说明。可显式说明。步长步长 11 或或 -1(-1(REVERSE)REVERSE) ,,循环次数循环次数 :: 上界上界 -- 下界下界

+1;+1;EXITEXIT 或或 EXIT WHENEXIT WHEN 可用在可用在 FORFOR 循环中;循环中;已知循环次数时,可用已知循环次数时,可用 FORFOR 循环,也可用其它循环,也可用其它末知循环次数不能用末知循环次数不能用 FORFOR 循环循环上界或下界可以为表达式。上界或下界可以为表达式。

Page 30: 第14章  PL/SQL 语言基础

例例 55 :显示:显示 2020 到到 5050 的平方根的值及它们的和。的平方根的值及它们的和。DECLAREDECLARE S FLOAT :=0;S FLOAT :=0;BEGINBEGIN FORFOR I I ININ 20..50 20..50 LOOPLOOP DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQRT(I),'9.9999'));DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQRT(I),'9.9999'));

S:=S+SQRT(I);S:=S+SQRT(I); END LOOPEND LOOP;; DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));

END;END;

说明:循环变量说明:循环变量 II 不用说明。不用说明。

Page 31: 第14章  PL/SQL 语言基础

例例 66: : 步长步长 -1-1 。加。加 REVERSEREVERSE 。。说明说明:加:加 REVERSEREVERSE ,, DECLAREDECLARE

S FLOAT :=0;S FLOAT :=0;

BEGINBEGIN

FOR I IN FOR I IN REVERSE 20..50REVERSE 20..50 LOOP LOOP

DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQRT(I),'9.9999'));DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQRT(I),'9.9999'));

S:=S+SQRT(I);S:=S+SQRT(I);

END LOOP;END LOOP;

DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));

END;END;

上界仍要大于下界。上界仍要大于下界。

Page 32: 第14章  PL/SQL 语言基础

例例 77:: 上下界为表达式的上下界为表达式的 FORFOR 循环循环DECLAREDECLARE

S FLOAT :=0;S FLOAT :=0;

N INT :=10;N INT :=10;

BEGINBEGIN

FOR I IN FOR I IN REVERSEREVERSE 2*N-12*N-1..N*N LOOP..N*N LOOP DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQRT(I),'9.9999'));DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQRT(I),'9.9999'));

S:=S+SQRT(I);S:=S+SQRT(I);

END LOOP;END LOOP;

DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));

END;END;

Page 33: 第14章  PL/SQL 语言基础

例例 8:8: 生成字符串生成字符串 SWJ001-SWJ120SWJ001-SWJ120declaredeclare n number(1);n number(1); sn varchar2(8);sn varchar2(8); sn1 char(3);sn1 char(3); beginbegin for n in 1..120 loopfor n in 1..120 loop if n<10 thenif n<10 then sn1:=ltrim(to_char(n,'9'));sn1:=ltrim(to_char(n,'9')); sn:=rtrim('swj00'||sn1);sn:=rtrim('swj00'||sn1); else if n<100 thenelse if n<100 then sn1:=ltrim(to_char(n,'99'));sn1:=ltrim(to_char(n,'99')); sn:=rtrim('swj0'||sn1); sn:=rtrim('swj0'||sn1); elseelse sn1:=ltrim(to_char(n,'999'));sn1:=ltrim(to_char(n,'999')); sn:=rtrim('swj'||sn1); sn:=rtrim('swj'||sn1); end if ;end if ; end if;end if; DBMS_OUTPUT.PUT_LINE(SN);DBMS_OUTPUT.PUT_LINE(SN); end loop; end loop; End;End;

Page 34: 第14章  PL/SQL 语言基础

4. 5 4. 5 循环嵌套循环嵌套上面的任何循环都可以互相嵌套,且可以多重嵌上面的任何循环都可以互相嵌套,且可以多重嵌套,但必须是完全嵌套。如:套,但必须是完全嵌套。如:LOOP LOOP … … FOR … LOOPFOR … LOOP … … ---- 可有其它循环可有其它循环 (( 多重循多重循

环环 )) END LOOP;END LOOP; … … WHILE … LOOPWHILE … LOOP … … ---- 可有其它循环可有其它循环 (( 多重循多重循

环环 )) END LOOP;END LOOP;END LOOP;END LOOP;

Page 35: 第14章  PL/SQL 语言基础

例例 99: : 两重循环,计算两重循环,计算 S=1!+2!+…+10!S=1!+2!+…+10!DECLAREDECLARE S FLOAT :=0;S FLOAT :=0; N INT :=10;N INT :=10; K INT ;K INT ;BEGINBEGIN FOR I IN 1..N LOOP -- FOR I IN 1..N LOOP -- 计算阶乘和计算阶乘和 K:=1;K:=1; FOR J IN 1..FOR J IN 1..I I LOOP --LOOP -- 计算计算 K!K! K:=K*J;K:=K*J; END LOOP;END LOOP; S:=S+K;S:=S+K; DBMS_OUTPUT.PUT_LINE(TO_CHAR(K));DBMS_OUTPUT.PUT_LINE(TO_CHAR(K));

END LOOP;END LOOP; DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));

END;END;

Page 36: 第14章  PL/SQL 语言基础

4.6 4.6 循环标签循环标签循环标签是以用来标示循环循环标签是以用来标示循环 ,,放在循环前。其格式:放在循环前。其格式: <<<< 标签名标签名 >>>> DECLAREDECLARE

S FLOAT :=0;S FLOAT :=0; N INT :=10;N INT :=10; K INT ;K INT ;BEGINBEGIN <<FOR_LOOP1>><<FOR_LOOP1>> FOR I IN 1..N LOOP -- FOR I IN 1..N LOOP -- 计算阶乘和计算阶乘和 K:=1;K:=1; <<FOR_LOOP2>><<FOR_LOOP2>> FOR J IN 1..I LOOP --FOR J IN 1..I LOOP -- 计算计算 K!K! K:=K*J;K:=K*J; END LOOP END LOOP FOR_LOOP2FOR_LOOP2;; S:=S+K;S:=S+K; DBMS_OUTPUT.PUT_LINE(TO_CHAR(K));DBMS_OUTPUT.PUT_LINE(TO_CHAR(K)); END LOOP END LOOP FOR_LOOP1;FOR_LOOP1; DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));DBMS_OUTPUT.PUT_LINE('S= '||TO_CHAR(S));END;END;

Page 37: 第14章  PL/SQL 语言基础

循环标签一是提高程序的可读性,二是可以从内循环标签一是提高程序的可读性,二是可以从内循环跳到外层。循环跳到外层。<<outer>>LOOP... LOOP ... EXIT outer WHEN ... – 退出两重循环。 END LOOP;...END LOOP outer;

注意注意:只能从内循环跳到外循环,反之不行。:只能从内循环跳到外循环,反之不行。

Page 38: 第14章  PL/SQL 语言基础

五、五、 %%TYPETYPE 类型类型PL/SQLPL/SQL 变量用来存储表中的数据,但二者要有相变量用来存储表中的数据,但二者要有相同类型。要保证变量与列名类型总是一致,就要同类型。要保证变量与列名类型总是一致,就要用用 %%TYPETYPE 类型。类型。 变量名 表名变量名 表名 .. 列名列名 %%TYPETYPE;;

例例 11 :: DECLAREDECLARE J_T J_T JOBS.JOB_TITLE%TYPEJOBS.JOB_TITLE%TYPE;; BEGINBEGIN SELECT JOB_TITLE SELECT JOB_TITLE INTO J_TINTO J_T FROM JOBS WHERE JOB_ID='AD_VP';FROM JOBS WHERE JOB_ID='AD_VP'; DBMS_OUTPUT.PUT_LINE(J_T);DBMS_OUTPUT.PUT_LINE(J_T); END;END;

Page 39: 第14章  PL/SQL 语言基础

六、六、 %%ROWTYPEROWTYPE 类型类型用用 %%ROWTYPEROWTYPE 说明变量为一个记录类型。说明变量为一个记录类型。 变量名 表名变量名 表名 %%ROWTYPE;ROWTYPE;

引用变量时:引用变量时:变量名变量名 .. 列名列名例例 11 :: DECLAREDECLARE EMP EMP EMPLOYEES %ROWTYPEEMPLOYEES %ROWTYPE;;BEGINBEGIN SELECT * INTO EMP FROM EMPLOYEES SELECT * INTO EMP FROM EMPLOYEES

WHERE EMPLOYEE_ID='201';WHERE EMPLOYEE_ID='201'; DBMS_OUTPUT.PUT_LINEDBMS_OUTPUT.PUT_LINE ((EMP.EMP.LAST_NAME||' '||LAST_NAME||' '||EMP.EMP.FIRST_NAME);FIRST_NAME);END;END;

Page 40: 第14章  PL/SQL 语言基础

七、游标七、游标 ((CURSOR)CURSOR)

游标是将从表中选择的一组记录,放置在内存的游标是将从表中选择的一组记录,放置在内存的临时表中。临时表中。游标是数据类型,要先说明后使用游标是数据类型,要先说明后使用。。1.1. 说明游标说明游标 CURSOR CURSOR 游标名 游标名 IS SELECTIS SELECT 语句;语句;例例 11: : DECLAREDECLARE MIN_S JOBS.MIN_SALARYMIN_S JOBS.MIN_SALARY%TYPE;%TYPE; CURSORCURSOR MS MS ISIS SELECT * FROM JOBS SELECT * FROM JOBS WHERE MIN_SALARY>=MIN_S;WHERE MIN_SALARY>=MIN_S; BEGINBEGIN NULLNULL; --; -- 空语句空语句 END;END;

Page 41: 第14章  PL/SQL 语言基础

2. 2. 打开游标打开游标 OPEN OPEN 游标名;游标名;注意注意:打开之前,游标中的变量必须有值;打开:打开之前,游标中的变量必须有值;打开游标后游标后 ,, 查询记录放在内存查询记录放在内存 ,, 指针指向第一个记录。指针指向第一个记录。例例 22 :: DECLAREDECLARE MIN_S JOBS.MIN_SALARYMIN_S JOBS.MIN_SALARY%TYPE;%TYPE; CURSORCURSOR MS MS ISIS SELECT * FROM JOBS SELECT * FROM JOBS WHERE MIN_SALARY>=WHERE MIN_SALARY>=MIN_SMIN_S;; BEGINBEGIN MIN_S:=1000; MIN_S:=1000; ---- 先给变量赋值先给变量赋值 OPEN MSOPEN MS; -- ; -- 才能打开游标才能打开游标 END;END;

Page 42: 第14章  PL/SQL 语言基础

3. 3. 提取游标数据提取游标数据 FETCH FETCH 游标名 游标名 INTO INTO 变量变量 1,1, 变量变量 2,…;2,…;

注意注意 : : 变量要与说明游标时变量要与说明游标时 SELECTSELECT 后的列名在后的列名在类类

型和个数上完成一样。不能只提取部分。型和个数上完成一样。不能只提取部分。 FETCH MS INTO J1FETCH MS INTO J1 ,, J2J2 ,, M1M1 ,, M2M2 ;;4. 4. 关闭游标关闭游标 CLOSE CLOSE 游标;游标; CLOSE MSCLOSE MS ;; 关闭后的游标不能再使用。关闭后的游标不能再使用。使用游标的过程使用游标的过程:说明游标、变量赋值、打开游:说明游标、变量赋值、打开游标、处理、关闭游标。标、处理、关闭游标。

Page 43: 第14章  PL/SQL 语言基础

例例 33 :提出数据:提出数据DECLAREDECLARE J1 JOBS.JOB_ID%TYPE; --J1 JOBS.JOB_ID%TYPE; -- 变量名与列名类型保持一致变量名与列名类型保持一致 J2 JOBS.JOB_TITLE%TYPE;J2 JOBS.JOB_TITLE%TYPE; M1 JOBS.MIN_SALARY%TYPE;M1 JOBS.MIN_SALARY%TYPE; M2 JOBS.MAX_SALARY%TYPE;M2 JOBS.MAX_SALARY%TYPE; MIN_S JOBS.MIN_SALARY%TYPE;MIN_S JOBS.MIN_SALARY%TYPE; CURSOR MS ISCURSOR MS IS SELECT * FROM JOBS SELECT * FROM JOBS ---- 说明游标说明游标 WHERE MIN_SALARY>=MIN_S;WHERE MIN_SALARY>=MIN_S; BEGINBEGIN MIN_S:=1000; --MIN_S:=1000; -- 先给变量赋值先给变量赋值 OPEN MS; -- OPEN MS; -- 才能打开游标才能打开游标 FETCH MS INTO J1,J2,M1,M2; --FETCH MS INTO J1,J2,M1,M2; -- 第一条记录第一条记录 DBMS_OUTPUT.PUT_LINE(J1||' '||J2||' '||TO_CHAR(m1+m2));DBMS_OUTPUT.PUT_LINE(J1||' '||J2||' '||TO_CHAR(m1+m2)); FETCH MS INTO J1,J2,M1,M2; --FETCH MS INTO J1,J2,M1,M2; -- 第二条记录第二条记录 DBMS_OUTPUT.PUT_LINE(J1||' '||J2||' '||TO_CHAR(m1+m2));DBMS_OUTPUT.PUT_LINE(J1||' '||J2||' '||TO_CHAR(m1+m2)); FETCH MS INTO J1,J2,M1,M2; --FETCH MS INTO J1,J2,M1,M2; -- 第三条记录第三条记录 DBMS_OUTPUT.PUT_LINE(J1||' '||J2||' '||TO_CHAR(m1+m2));DBMS_OUTPUT.PUT_LINE(J1||' '||J2||' '||TO_CHAR(m1+m2));END;END;

Page 44: 第14章  PL/SQL 语言基础

例例 44: : 复杂游标(分组)复杂游标(分组)DECLAREDECLARE DEP EMPLOYEES.DEPARTMENT_ID%TYPE; DEP EMPLOYEES.DEPARTMENT_ID%TYPE; COU INT;COU INT; CURSORCURSOR DEPT IS DEPT IS SELECT DEPARTMENT_ID,COUNT(*) FROMSELECT DEPARTMENT_ID,COUNT(*) FROM EMPLOYEES EMPLOYEES GROUP BYGROUP BY DEPARTMENT_ID; DEPARTMENT_ID;BEGINBEGIN OPENOPEN DEPT; -- DEPT; -- 打开游标打开游标 FETCH FETCH DEPT INTO DEP,COU; --DEPT INTO DEP,COU; -- 第一条记录第一条记录 DBMS_OUTPUT.PUT_LINE(DEP||'DBMS_OUTPUT.PUT_LINE(DEP||' 的人数是: 的人数是: '||'||TO_CHAR(COU));TO_CHAR(COU));

FETCHFETCH DEPT INTO DEP,COU; -- DEPT INTO DEP,COU; -- 第二条记录第二条记录 DBMS_OUTPUT.PUT_LINE(DEP||'DBMS_OUTPUT.PUT_LINE(DEP||' 的人数是: 的人数是: '||'||TO_CHAR(COU));TO_CHAR(COU));

CLOSECLOSE DEPT; -- DEPT; -- 关闭游标关闭游标ENDEND;;

Page 45: 第14章  PL/SQL 语言基础

5. 5. 游标属性游标属性 通过游标属性来知道游标的状态。通过游标属性来知道游标的状态。A: %FOUND A: %FOUND

如果前一个如果前一个 FETCHFETCH 返回一行,返回一行, %%FOUNDFOUND 返回返回TRUETRUE ;;否则返回否则返回 FALSEFALSE 。。在未打开游标之前设在未打开游标之前设置置 %%FOUNDFOUND ,,返回错误返回错误 ORA_1001ORA_1001 。。用法:用法: 游标名游标名 %%FOUNDFOUND

B.B. %NOTFOUND%NOTFOUND

与与 %%FOUNDFOUND 相反,常用于退出循环提出。相反,常用于退出循环提出。C. %ISOPENC. %ISOPEN

判定游标是否打开。打开为判定游标是否打开。打开为 TRUE,TRUE, 否则为否则为FALSE.FALSE.

Page 46: 第14章  PL/SQL 语言基础

D.D. %ROWCOUNT%ROWCOUNT

返回从游标中已提取的行数。返回从游标中已提取的行数。%%FOUNDFOUND %%NOTFOUNDNOTFOUND %%ISOPENISOPEN %%ROWCOUNTROWCOUNT

打开之前打开之前 出错出错 出错出错 FALSEFALSE 出错出错

打开之后打开之后 NULLNULL NULLNULL TRUETRUE 00

11FETCHFETCH 前前 NULLNULL NULLNULL TRUETRUE 00

11FETCHFETCH 后后 TRUETRUE FALSEFALSE TRUETRUE 11

下下 FETCHFETCH 前前 TRUETRUE FALSEFALSE TRUETRUE 11

下下 FETCHFETCH 后后 TRUETRUE FALSEFALSE TRUETRUE 以数据个数以数据个数

最最 FETCHFETCH 前前 TRUETRUE FALSEFALSE TRUETRUE 以数据个数以数据个数

最最 FETCHFETCH 后后 FALSEFALSE TRUETRUE TRUETRUE 以数据个数以数据个数

CLOSECLOSE 后后 出错出错 出错出错 FALSEFALSE 出错出错

Page 47: 第14章  PL/SQL 语言基础

例例 55 :: declaredeclare emp employees emp employees %rowtype%rowtype; ; cursorcursor sal sal is select * is select * into empinto emp from employees from employees where salary>=10000; --where salary>=10000; -- 说明游标说明游标beginbegin open sal; -- open sal; -- 打开游标打开游标 looploop fetch sal into emp;fetch sal into emp; if if sal%foundsal%found then -- then -- 提出成功提出成功 dbms_output.put_linedbms_output.put_line (emp.last_name||' (emp.last_name||' 工资工资 :'||:'||to_char(emp.salary)); to_char(emp.salary)); else -- else -- 不成功不成功 exit;exit; end if;end if; end loop;end loop;end;end;

Page 48: 第14章  PL/SQL 语言基础

例例 66 :测试游标属性:测试游标属性declaredeclare emp employees %rowtype;emp employees %rowtype; cursor cursor sal is select * into emp from employees sal is select * into emp from employees where department_id=100;where department_id=100;beginbegin if not if not sal%isopensal%isopen then -- then -- 游标未打开游标未打开 open sal;open sal; end if;end if; dbms_output.put_line('dbms_output.put_line(' 提取行数:提取行数: '||'||to_char(to_char(sal%rowcountsal%rowcount)); ));

looploop fetch sal into emp; fetch sal into emp; dbms_output.put_line(emp.last_name||'dbms_output.put_line(emp.last_name||' 行行 :'||:'||to_char(sal%rowcount));to_char(sal%rowcount)); exit when exit when sal%notfoundsal%notfound or or sal%rowcountsal%rowcount>=5;>=5; end loop;end loop;end;end;

Page 49: 第14章  PL/SQL 语言基础

例例 77: : 有表有表 DATA_FIEL(n1,n2,n3,exnum)DATA_FIEL(n1,n2,n3,exnum) 和表和表 TEMPTEMP

DECLAREDECLARE num1 data_table.n1%TYPE; num1 data_table.n1%TYPE; num2 data_table.n2%TYPE; num2 data_table.n2%TYPE; num3 data_table.n3%TYPE; num3 data_table.n3%TYPE; result temp.col1%TYPE;result temp.col1%TYPE; CURSOR CURSOR c1 ISc1 IS SELECT n1, n2, n3 FROM data_tableSELECT n1, n2, n3 FROM data_table WHERE exnum = 1;WHERE exnum = 1;BEGINBEGIN OPEN c1;OPEN c1; LOOPLOOP FETCH c1 INTO num1, num2, num3;FETCH c1 INTO num1, num2, num3; EXIT WHEN EXIT WHEN c1%NOTFOUNDc1%NOTFOUND; ; result := num2/(num1 + num3);result := num2/(num1 + num3); INSERT INTO temp VALUES (result, NULL, NULL);INSERT INTO temp VALUES (result, NULL, NULL); END LOOP;END LOOP; CLOSE c1;CLOSE c1; COMMIT;COMMIT;END;END;

Page 50: 第14章  PL/SQL 语言基础

八、参数化游标和隐含游标八、参数化游标和隐含游标1.1. 参数化游标参数化游标 CRUSOR CRUSOR 游标名游标名 (( 变量变量 1 1 类型类型 1,1, 变量变量 2 2 类型类型 2,2,

…)…) IS SELECTIS SELECT 语句语句说明说明:: SELECTSELECT 语句的条件中使用变量语句的条件中使用变量 ,, 变量类型变量类型可以为可以为 %%TYPETYPE 。。打开参数化游标:打开参数化游标: OPEN OPEN 游标名游标名 ((实参实参 1,1,实参实参 2,…);2,…);

说明说明:在打开时所有实参要有具体值,且在数量:在打开时所有实参要有具体值,且在数量和类型上与游标说明时一致。和类型上与游标说明时一致。 实参可以是表达式。实参可以是表达式。

Page 51: 第14章  PL/SQL 语言基础

例例 11 :带参数游标:带参数游标DECLAREDECLARE EMP EMPLOYEES%ROWTYPE;EMP EMPLOYEES%ROWTYPE;CURSOR CURSOR c1(S1 EMPLOYEES.SALARY%TYPE,c1(S1 EMPLOYEES.SALARY%TYPE, DID INT)DID INT) IS SELECT * FROM EMPLOYEES IS SELECT * FROM EMPLOYEES

WHERE SALARY>=S1 and DEPARTMENT_ID=WHERE SALARY>=S1 and DEPARTMENT_ID=diddid;;BEGINBEGIN OPEN OPEN c1(10000,90)c1(10000,90);; LOOP LOOP FETCH c1 INTO EMP;FETCH c1 INTO EMP; DBMS_OUTPUT.PUT_LINE(TO_CHAR(C1%ROWCOUNT));DBMS_OUTPUT.PUT_LINE(TO_CHAR(C1%ROWCOUNT)); EXIT WHEN c1%NOTFOUND;EXIT WHEN c1%NOTFOUND; END LOOP;END LOOP; CLOSE c1;CLOSE c1;END;END;

Page 52: 第14章  PL/SQL 语言基础

例例 2: 2: 带参数游标带参数游标declaredeclare cursor c1(cursor c1(s1 employees.salary%types1 employees.salary%type) is select ) is select

max(salary),min(salary)max(salary),min(salary) from employees where salary>=s1;from employees where salary>=s1; m1 employees.salary%type:=16000;m1 employees.salary%type:=16000; m2 employees.salary%type:=6000;m2 employees.salary%type:=6000;beginbegin open c1(open c1((m1+m2)/2(m1+m2)/2); --); --实参为表达式实参为表达式 looploop fetch c1 into m1,m2;fetch c1 into m1,m2; if if c1%foundc1%found then then insert into jobs values ('new_j','new job',m1,m2);insert into jobs values ('new_j','new job',m1,m2); end if;end if; dbms_output.put_line(to_char(c1%rowcount));dbms_output.put_line(to_char(c1%rowcount)); exit when c1%notfound;exit when c1%notfound; end loop;end loop; close c1;close c1; commit; --commit; -- 提交游标提交游标end;end;

Page 53: 第14章  PL/SQL 语言基础

2. 2. 隐含游标(隐含游标( SQLSQL 游标游标 ))

每次处理一个每次处理一个 SQLSQL 语句,语句, ORACLEORACLE自动打开一个自动打开一个游标,该游标游标,该游标不能使用不能使用 OPEN,FETCHOPEN,FETCH 或或 CLOSECLOSE 进进行操作。但可用游标特性来获得执行行操作。但可用游标特性来获得执行 SQLSQL 的信息。的信息。隐含游标的名字是隐含游标的名字是:: SQLSQL

SQLSQL 游标总是反映最后一个游标总是反映最后一个 SQLSQL 语句执行情况。语句执行情况。%%ISOPENISOPEN 永远是永远是 FALSE(FALSE( 执行完执行完 SQLSQL 后自动关后自动关闭)闭)

%%FOUNDFOUND 至少处理一行至少处理一行 ,, 为为 TRUE;TRUE; 否则为否则为FALSEFALSE

%NOTFOUND%NOTFOUND 与与 %%FOUNDFOUND 相反相反%%ROWCOUNTROWCOUNT 处理影响的行数。处理影响的行数。

Page 54: 第14章  PL/SQL 语言基础

例例 33: : 隐含游标的属性使用隐含游标的属性使用beginbegin delete from jobs where job_id like 'ddad%';delete from jobs where job_id like 'ddad%'; if if sql%foundsql%found then then dbms_output.put_line('dbms_output.put_line(' 删除行数删除行数 : '||: '||to_char(to_char(sql%rowcount)sql%rowcount)););

elseelse dbms_output.put_line('dbms_output.put_line(' 没有删除任何行没有删除任何行 ');'); end if;end if; update jobs set max_salary=(max_salary+min_salary)/2, update jobs set max_salary=(max_salary+min_salary)/2, min_salary=(max_salary-min_salary)/2min_salary=(max_salary-min_salary)/2 where job_id like 'ad%';where job_id like 'ad%'; if if sql%foundsql%found then then dbms_output.put_line(‘dbms_output.put_line(‘ 改行数改行数 :'||:'||to_char(to_char(sqlsql

%rowcount%rowcount));)); elseelse dbms_output.put_line('dbms_output.put_line(' 没有修改任何行没有修改任何行 ');'); end if;end if;end;end;

Page 55: 第14章  PL/SQL 语言基础

上机题:上机题:1.1. 计算计算 11 !! +2+2 !! +3+3 !…!… +10!+10! 的值。的值。2.2. 计算 计算 x/1!+x^2/2!+...+x^n/n! (x/1!+x^2/2!+...+x^n/n! ( 其中其中 XX ==

2,n=10) 2,n=10) 3.3. 编程序求满足不等式 编程序求满足不等式 1+3^2+5^2+…+1+3^2+5^2+…+N^2>2000N^2>2000

的最小的最小 NN 值。值。4.4. 计算下面级数当末项小于计算下面级数当末项小于 0.0010.001 时的部分和。 时的部分和。

1/(1*2)+1/(2*3)+1/(3*4)+…+1/(1/(1*2)+1/(2*3)+1/(3*4)+…+1/(n*(n+1))+ ……n*(n+1))+ ……5.5. 计算并输出计算并输出 1900-20001900-2000 之间的素数的个数之间的素数的个数 NN6.6. 定义游标:从雇员表中显示工资大于定义游标:从雇员表中显示工资大于 1000010000 的的

记录,只要姓名、部门编号和工资。编程显示记录,只要姓名、部门编号和工资。编程显示其中的奇数记录。其中的奇数记录。

7.7. 定义游标:列出每个员工的姓名、部门名称。定义游标:列出每个员工的姓名、部门名称。编程显示第编程显示第 1010 个到第个到第 2020 个记录。个记录。

Page 56: 第14章  PL/SQL 语言基础

8. 8. 在在 JOBSJOBS 表中删除工作编号为表中删除工作编号为 AD_NEWAD_NEW 的记的记录,如果无录,如果无,,插入插入(‘(‘AD_NEW’,’POLICE’,1999,20000)AD_NEW’,’POLICE’,1999,20000)

9. 9. 将雇员表中的所有工资小于将雇员表中的所有工资小于 1000010000 增加增加 10001000 ,,统计出增加工资的人数及增加的工资数量。统计出增加工资的人数及增加的工资数量。

10. 10. 将雇员表中的部门编号为将雇员表中的部门编号为 100100 的所有员工删除,的所有员工删除,统计删除的人数及删除人的平均工资。统计删除的人数及删除人的平均工资。

11. 11. 编程输出编程输出 9*99*9 乘法表。乘法表。12. 12. 从雇员表中显示工资最高的前五个人的姓名,从雇员表中显示工资最高的前五个人的姓名,

部门和工资。部门和工资。

Page 57: 第14章  PL/SQL 语言基础

第五章 过程、函数、触发器第五章 过程、函数、触发器无名块只能以文件形式执行、不存放在数据库中,无名块只能以文件形式执行、不存放在数据库中,每次执行要编译,不能在其它每次执行要编译,不能在其它 PL/SQLPL/SQL 块中调用。块中调用。过程、函数和触发器都是有名块,是数据库对象过程、函数和触发器都是有名块,是数据库对象一、过程设计一、过程设计1.1. 创建过程创建过程 (( 系统权限系统权限 CREATE PROCEDURE)CREATE PROCEDURE)

过程结构如下:过程结构如下:CREATE OR REPLACE PROCEDURECREATE OR REPLACE PROCEDURE 过程名过程名 (( 参数列表参数列表 ) ) ASAS

说明部分 说明部分 ---- 内部变量内部变量BEGINBEGIN 执行部分执行部分[[EXCEPTION EXCEPTION 异常处理部分异常处理部分 ]]END [END [ 过程名过程名 ]]

Page 58: 第14章  PL/SQL 语言基础

说明说明:过程必须有名字:过程必须有名字 ;; 过程可以有参数或无参数过程可以有参数或无参数创建过程经编译无错后存放在数据库中创建过程经编译无错后存放在数据库中 (( 不马上执不马上执行行 )) ;调用过程时执行块内语句。;调用过程时执行块内语句。过程的使用过程的使用:先:先创建后调用。创建后调用。例例 11. . Create or replace procedure test1 as Create or replace procedure test1 as sal employees.salary%type;sal employees.salary%type; beginbegin select salary into sal from employeesselect salary into sal from employees where last_name=‘Abel’;where last_name=‘Abel’; dbms_output.put_line(to_char(sal));dbms_output.put_line(to_char(sal)); end;end;注意注意 :: 即使程序编译有错,过程也将写入数据库。即使程序编译有错,过程也将写入数据库。

Page 59: 第14章  PL/SQL 语言基础

2.2. 查询过程查询过程 USER_SOURCEUSER_SOURCE

USER_SOURCEUSER_SOURCE: : NAMENAME 、、 TEXTTEXT 、、 TYPETYPE 、、 LINELINE

SELECT TEXT FROM USER_SOURCESELECT TEXT FROM USER_SOURCE

WHERE NAME=‘TTT’WHERE NAME=‘TTT’

ORDER BY LINE;ORDER BY LINE;

3. 3. 修改过程修改过程存储过程以文件形式存在。在存储过程以文件形式存在。在 SQL PLUSSQL PLUS 中:中:@@CCC.SQLCCC.SQL

EDITEDIT

4. 4. 调用过程调用过程 ((EXECUTE ANY PROCEDURE)EXECUTE ANY PROCEDURE)

在块中或过程中调用存储过程,不能在表达式。在块中或过程中调用存储过程,不能在表达式。

Page 60: 第14章  PL/SQL 语言基础

调用方式调用方式:过程名:过程名 [([( 实参实参 1,…,1,…, 实参实参 N)]N)]

例例 22: : 用户用户 SWJ001SWJ001 :: BEGINBEGIN TEST1;TEST1; END;END;例例 3:3:SWJ001:SWJ001:GRANT GRANT EXECUTE ON TEST1EXECUTE ON TEST1 TO HR; TO HR;

HRHR 用户用户:: BEGIN BEGIN SWJ001SWJ001.TEST1; .TEST1; END; END; 5. 5. 删除过程删除过程 DROP PROCEDURE DROP PROCEDURE 过程名过程名例例 44: : DROP PROCEDURE TEST1;DROP PROCEDURE TEST1;

Page 61: 第14章  PL/SQL 语言基础

6. 6. 带参数的过程带参数的过程CREATE OR REPLACE PROCEDURE CREATE OR REPLACE PROCEDURE 过程名过程名 [[(( 参数参数 1 [1 [IN|OUT|IN OUT] IN|OUT|IN OUT] 类型类型 11,,…,…,))] ] ASAS [[ 内部变量说明内部变量说明 ]]BEGINBEGIN 执行部分执行部分   [[EXCEPTIONEXCEPTION

异常处理异常处理 ]]ENDEND ;;说明说明:: IN IN 向过程送参数,读入参数向过程送参数,读入参数OUT: OUT: 从过程获得参数,输出参数从过程获得参数,输出参数IN OUT IN OUT 即可以读入参数,可也获得参数即可以读入参数,可也获得参数

Page 62: 第14章  PL/SQL 语言基础

例例 55: :

create or replace procedure test2create or replace procedure test2(( v1 in employees.job_id%type, --v1 in employees.job_id%type, -- 参数说明参数说明 v2 out employees.salary%typev2 out employees.salary%type) as) as vv employees.salary%type;--vv employees.salary%type;-- 内部变量说明内部变量说明 beginbegin select max(salary) into vv from employees whereselect max(salary) into vv from employees where job_id like v1;job_id like v1; v2:=vv+10000; --OUTv2:=vv+10000; --OUT 类型参数必须赋值类型参数必须赋值 end;end;调用调用:: declare declare v employees.salary%type;v employees.salary%type; beginbegin test2(‘AD%',v);test2(‘AD%',v); dbms_output.put_line(to_char(v));dbms_output.put_line(to_char(v)); end;end;

Page 63: 第14章  PL/SQL 语言基础

例例 66 :求阶乘:求阶乘 create or replace procedure jccreate or replace procedure jc(v1(v1 in in int, v2 int, v2 outout int) int)

asas s int;s int; beginbegin s:=1;s:=1; for i in 1..for i in 1..v1 v1 looploop s:=s*i;s:=s*i; end loop;end loop; v2:=s;v2:=s; dbms_output.put_line(dbms_output.put_line('' 过程内过程内 V2V2 值值 :'||:'||

to_char(s));to_char(s)); end;end;调用调用: : declaredeclare k int:=10;k int:=10; beginbegin jc(k,k);jc(k,k); dbms_output.Put_line('dbms_output.Put_line(' 过程外过程外 K:'||to_char(k));K:'||to_char(k)); end;end;

Page 64: 第14章  PL/SQL 语言基础

注意注意::过程调用参数类型与个数必须完全一致;过程调用参数类型与个数必须完全一致;OUTOUT 或或 IN OUTIN OUT 参数在调用时不能对应表达式;参数在调用时不能对应表达式;

例:例: JC(K+1,K);--JC(K+1,K);--正确 但正确 但 JC(K+1,K*2);JC(K+1,K*2); 非法非法参数表示对应表列时,最好参数表示对应表列时,最好%%TYPETYPE 类型类型过程调用只能出现在块中,不能与表达式计算过程调用只能出现在块中,不能与表达式计算可以多个可以多个 OUTOUT 参数来返回多个值。参数来返回多个值。ININ 参数在过程中不能赋值参数在过程中不能赋值如果要给参数赋值,必须指定为如果要给参数赋值,必须指定为 OUTOUT 或或 IN OUTIN OUT不指明不指明 ININ 、、 OUTOUT 或或 IN OUTIN OUT 时,缺省为时,缺省为 ININ出错信息表出错信息表 USER_ERRORSUSER_ERRORS(( 列:列: LINE,TEXT,..)LINE,TEXT,..)

Page 65: 第14章  PL/SQL 语言基础

例例 77:: 在过程中用游标在过程中用游标 ((返回第返回第 NN 个不等于的记录个不等于的记录 ))create or replace procedure jobk(create or replace procedure jobk( j in jobs.job_id%type, j in jobs.job_id%type, jk out jobs%rowtypejk out jobs%rowtype, n in , n in

int) asint) as cursor j_c iscursor j_c is select * from jobs where job_id<>j; select * from jobs where job_id<>j; k int;k int;beginbegin k:=1;k:=1; if not j_c%isopen thenif not j_c%isopen then open j_c;open j_c; end if;end if; looploop fetch j_c into jk;fetch j_c into jk; exit when n=k;exit when n=k; k:=k+1;k:=k+1; end loop;end loop; close j_c;close j_c;end;end;

Page 66: 第14章  PL/SQL 语言基础

调用:调用:declaredeclare jj jobs%rowtype;jj jobs%rowtype;beginbegin jobk('ST_MAN',jj,3);jobk('ST_MAN',jj,3); dbms_output.put_line(jj.job_id||' '||jj.job_title);dbms_output.put_line(jj.job_id||' '||jj.job_title); jobk('FI_MGR',jj,5);jobk('FI_MGR',jj,5); dbms_output.put_line(jj.job_id||' '||jj.job_title);dbms_output.put_line(jj.job_id||' '||jj.job_title);end;end;

Page 67: 第14章  PL/SQL 语言基础

例例 88: : 显示表显示表 EMPLOYEESEMPLOYEES 的第的第 NN 条记录的内容条记录的内容create or replace procedure create or replace procedure n_recordn_record(n int,(n int, emp out employees%rowtype) emp out employees%rowtype) asas k int;k int; cursor e_c is select * from employees;cursor e_c is select * from employees;beginbegin k:=1;k:=1; if not e_c %isopen thenif not e_c %isopen then open e_c;open e_c; end if;end if; looploop fetch e_c into emp;fetch e_c into emp; exit when e_c%notfound or k=n;exit when e_c%notfound or k=n; k:=k+1;k:=k+1; end loop;end loop; if k<>n thenif k<>n then dbms_output.put_line('NO FOUND');dbms_output.put_line('NO FOUND'); end if;end if;end;end;

Page 68: 第14章  PL/SQL 语言基础

例例 99: : 显示显示 M—NM—N 条记录的姓名和工资条记录的姓名和工资 create or replace procedure mn_record(m int ,create or replace procedure mn_record(m int , n int) n int) asas jj employees %rowtype;jj employees %rowtype; k int;k int; beginbegin k:=m;k:=m; looploop n_record(k,jj); --n_record(k,jj); -- 在在 mn_recordmn_record 过程中调用过过程中调用过

程程 dbms_output.put_line(jj.last_name||' '||to_char(jj.salary));dbms_output.put_line(jj.last_name||' '||to_char(jj.salary)); k:=k+1;k:=k+1; exit when k>n;exit when k>n; end loop;end loop; end;end;调用调用: : BEGINBEGIN mn_record(10,20);mn_record(10,20); END;END;

Page 69: 第14章  PL/SQL 语言基础

二、函数设计二、函数设计函数是命名块,可以有参数或无参数,但必须有函数是命名块,可以有参数或无参数,但必须有返回值,函数是用于表达式中而不能单独作为一返回值,函数是用于表达式中而不能单独作为一个命令行。其它与过程相似。个命令行。其它与过程相似。1.1. 建立函数建立函数CREATE OR REPLACE FUNCTION CREATE OR REPLACE FUNCTION 函数名函数名 (( 参数参数 1[1[IN|OUT|IN OUT],…) RETURN IN|OUT|IN OUT],…) RETURN 类型 类型

ASAS

内部参数说明内部参数说明BEGINBEGIN

执行部分或有异常处理执行部分或有异常处理END;END;

Page 70: 第14章  PL/SQL 语言基础

例例 11:: 判定整数判定整数 NN 是否为素数是否为素数create or replace function create or replace function pri(n int) pri(n int) return booleanreturn boolean as as k int;k int; flag boolean; flag boolean; ----去掉去掉 ii int;ii int; beginbegin k:=round(sqrt(n));k:=round(sqrt(n)); flag:=false;flag:=false; for I in 2..k loopfor I in 2..k loop ii:=i;ii:=i; exit when mod(n,i)=0;exit when mod(n,i)=0; end loop;end loop; if ii<k thenif ii<k then flag:=false; --return false;flag:=false; --return false; elsif mod(n,ii)=0 thenelsif mod(n,ii)=0 then flag:=false; --return false;flag:=false; --return false; elseelse flag:=true; --return true; flag:=true; --return true; end if;end if; return flag; --return flag; -- 去掉去掉 end;end;

Page 71: 第14章  PL/SQL 语言基础

例例 22 :显示:显示 22 到到 200200 之间的所有素数之间的所有素数 beginbegin

for i in 2..200 loopfor i in 2..200 loop

if if pri(i)pri(i) then then

dbms_output.put_line(to_char(i));dbms_output.put_line(to_char(i));

end if;end if;

end loop;end loop;

end;end;

Page 72: 第14章  PL/SQL 语言基础

例例 33 :函数中的游标:函数中的游标 create or replace function create or replace function dep return intdep return int as as cursor de is select department_id,count(*)cursor de is select department_id,count(*) from employees group by department_id;from employees group by department_id;S int:=0;S int:=0;D1 employees.department_id%type;D1 employees.department_id%type;I1 int;I1 int;BeginBegin open de;open de; looploop fetch de into d1,i1;fetch de into d1,i1; s:=s+i1;s:=s+i1; exit when de%notfound;exit when de%notfound; end loop;end loop; return s;return s;End; -- End; -- 无参数函数,调用时用无参数函数,调用时用 DEP()DEP() 或或 DEPDEP调用:调用: select dep()+10 from dual;select dep()+10 from dual;

Page 73: 第14章  PL/SQL 语言基础

2. 2. 删除函数和修改函数删除函数和修改函数修改函数是以文件存在修改函数是以文件存在 ,, 在在 SQL PLUS:get filenameSQL PLUS:get filename

删除函数:删除函数: DROP FUNCTION DROP FUNCTION 函数名;函数名;3. 3. 查询函数查询函数 ((USER_SOURCE)USER_SOURCE) NAME,TYPE,TEXT,LINENAME,TYPE,TEXT,LINE

三、子程序三、子程序1.1. 内置子程序内置子程序 ((Stored SubprogramStored Subprogram ::过程与函数过程与函数 ))用用 Create or replace Create or replace 建立的子程序是内置子程序,建立的子程序是内置子程序,它们存放在数据库中,它是数据库对象。任何位它们存放在数据库中,它是数据库对象。任何位置都可调用。置都可调用。USER_OBJECTSUSER_OBJECTS : : 用户所有对象信息用户所有对象信息USER_SOURCE,USER_ERROR(USER_SOURCE,USER_ERROR( 编译错误信息编译错误信息 ))

Page 74: 第14章  PL/SQL 语言基础

2. 2. 本地子程序本地子程序如果子程序是在如果子程序是在 PL/SQLPL/SQL 块中说明部分定义,叫本块中说明部分定义,叫本地子程序。它只能在本块中调用。本地子程序的地子程序。它只能在本块中调用。本地子程序的定义:定义: PROCEDURE PROCEDURE 子程序名子程序名 (( 参数表参数表 ) ) ASAS

说明部分说明部分 ; --; --

BEGINBEGIN

… …

END; END;

FUNCTION FUNCTION 函数名函数名 (( 参数表参数表 ) ) return return 类型 类型 ISIS

同过程定义同过程定义

Page 75: 第14章  PL/SQL 语言基础

例例 44: : 求求 1!+2!+…+10!1!+2!+…+10!DECLAREDECLARE s int :=0;s int :=0; FUNCTIONFUNCTION JC(n in int) return int as JC(n in int) return int as k int :=1;k int :=1; begin begin for I in 1..n loopfor I in 1..n loop k:=k*I;k:=k*I; end loop;end loop; return k;return k; endend;;BeginBegin for I in 1..10 loopfor I in 1..10 loop s:=s+jc(I);s:=s+jc(I); end loop;end loop;End;End;

Page 76: 第14章  PL/SQL 语言基础

注意注意:: 本地子程序只能放在说明部分的尾部本地子程序只能放在说明部分的尾部 本地子程序只能在说明它的本地子程序只能在说明它的 PL/SQLPL/SQL 块中的调用块中的调用 可以在内置子程序中定义本地子程序可以在内置子程序中定义本地子程序 本地子程序采用向前说明:即当有A和B两个子程序时,本地子程序采用向前说明:即当有A和B两个子程序时,B中调用A时,必须在A之间说明BB中调用A时,必须在A之间说明B

DECLAREDECLARE PROCEDURE B(…); --PROCEDURE B(…); -- 仅是说明仅是说明 ,, 无过程体无过程体 ,,向前说向前说

明明 PROCEDURE A(…) IS…PROCEDURE A(…) IS… PROCEDURE B(…) ISPROCEDURE B(…) IS … … BEGINBEGIN A(…); --A(…); -- 调用过程A调用过程A END;END;

Page 77: 第14章  PL/SQL 语言基础

四、包程序设计四、包程序设计包是将一些过程、函数和程序块集合在一起。包包是将一些过程、函数和程序块集合在一起。包由包头由包头 (( 包说明包说明 )) 和包体两部分,分开存储。建立可和包体两部分,分开存储。建立可包也分两步:建立包说明,建立包体。包也分两步:建立包说明,建立包体。1.1. 包说明包说明CREATE [OR REPLACE] PACKAGE CREATE [OR REPLACE] PACKAGE 包名 包名 IS|ASIS|AS

过程说明过程说明 || 函数说明函数说明 || 变量说明变量说明 || 异常说明异常说明 || 游标说游标说明明

END [END [ 包名包名 ]] ;;注意:注意: 要在包中建立的过程等必须先在包头中说明要在包中建立的过程等必须先在包头中说明 包部件可以任意次序,但必须使用之前说明包部件可以任意次序,但必须使用之前说明

Page 78: 第14章  PL/SQL 语言基础

在包说明中只说明过程和函数的名称及参数,包在包说明中只说明过程和函数的名称及参数,包的代码在包体中。的代码在包体中。

包中可能只有一种类型部件,如过程或函数等。包中可能只有一种类型部件,如过程或函数等。包说明中定义的变量在包体可以使用包说明中定义的变量在包体可以使用包体的名称必须与包说明的包名一样包体的名称必须与包说明的包名一样可以在包说明外到包变量赋值可以在包说明外到包变量赋值 : : EX.VAR1:=0;EX.VAR1:=0;

包体定义:包体定义:CREATE OR REPLACE CREATE OR REPLACE PACKAGE BODYPACKAGE BODY 包名 包名 ASASPROCEDURE… --PROCEDURE… -- 过程的实际代码过程的实际代码FUNCTION…FUNCTION… ---- 函数的实际代码函数的实际代码END [END [ 包名包名 ]] ;;

Page 79: 第14章  PL/SQL 语言基础

包中过程或函数调用:包中过程或函数调用:  包名  包名 .. 过程名或函数名过程名或函数名 [([( 实参表实参表 )])] ;;例例 1: 1: 建立包说明建立包说明CREATE OR REPLACE PACKAGE EXPP ASCREATE OR REPLACE PACKAGE EXPP AS

PROCEDURE PR(XX NUMBER);PROCEDURE PR(XX NUMBER);---- 仅有名字和参数仅有名字和参数

FUNCTION FN RETURN VARCHAR2;FUNCTION FN RETURN VARCHAR2;

VAR1 NUMBER;VAR1 NUMBER;

VAR2 VARCHAR2(30);VAR2 VARCHAR2(30);

VAR3 BOOLEAN;VAR3 BOOLEAN;

END EXPP;END EXPP;

包头中只定义过程或函数名及其参数。包头中只定义过程或函数名及其参数。

Page 80: 第14章  PL/SQL 语言基础

建立包体建立包体Create or replace package body expp Create or replace package body expp asasProcedure pr(xx number) asProcedure pr(xx number) asBeginBegin var1:=xx;var1:=xx;End;End;Function fu return varchar2 asFunction fu return varchar2 asBeginBegin var2:='TAXES';var2:='TAXES'; return VAR2||' '||to_char(var1);return VAR2||' '||to_char(var1);End;End;END EXPP;END EXPP;

Page 81: 第14章  PL/SQL 语言基础

包的使用:包的使用:BEGINBEGIN

EXPP.VAR3:=trueEXPP.VAR3:=true; --; -- 在包外为包内变量赋值在包外为包内变量赋值 EXPP.PR(2)EXPP.PR(2);;

DBMS_OUTPUT.PUT_LINE(DBMS_OUTPUT.PUT_LINE(EXPP.FUEXPP.FU););

END;END;

2. 2. 查询包信息查询包信息 (( 包头和包体包头和包体 ))

USER_SOURCEUSER_SOURCE,, 类型类型 PACKAGEPACKAGE 或或 PACKAGE PACKAGE BODYBODY

SELECT TEXT FROM USER_SOURCESELECT TEXT FROM USER_SOURCE

WHERE NAME=‘EXPP’ ANDWHERE NAME=‘EXPP’ AND

TYPE = ‘PACKAGE BODY’TYPE = ‘PACKAGE BODY’

Page 82: 第14章  PL/SQL 语言基础

3. 3. 修改包和删除包修改包和删除包修改时同过程修改。修改时同过程修改。删除包删除包DROP PACKAGE DROP PACKAGE 包名包名删除包时,包说明及包体全部删除。删除包时,包说明及包体全部删除。DROP PACKAGE BODY DROP PACKAGE BODY 包名包名仅删除包体仅删除包体 ..

例:例: DROP PACKAGE BODY EXPP;DROP PACKAGE BODY EXPP;

SELECT NAME FROM USER_SOURCESELECT NAME FROM USER_SOURCE

WHERE TYPE=‘PACKAGE’; --WHERE TYPE=‘PACKAGE’; -- 找到找到 EXPPEXPP

DROP PACKAGE EXPP;DROP PACKAGE EXPP;

Page 83: 第14章  PL/SQL 语言基础

五、触发器程序设计五、触发器程序设计触发器是有名块,是数据库对象,与过程相似。触发器是有名块,是数据库对象,与过程相似。但触发器是自动调用,且不接收参数。但触发器是自动调用,且不接收参数。1.1. 触发器建立触发器建立 (( 权限:权限: CREATE CREATE [ANY][ANY]

TRIGGER)TRIGGER)

CREATE OR REPLACE TRIGGER CREATE OR REPLACE TRIGGER 触发器名触发器名   [[BEFORE|AFTER] BEFORE|AFTER] 触发事件 触发事件 ON ON 表名表名   [[FOR EACH ROW ][WHEN FOR EACH ROW ][WHEN 触发条件触发条件 ]]

 触发体 触发体说明:说明:触发事件:触发事件: INSERTINSERT 、、 UPDATEUPDATE 、、 DELETEDELETE表名:触发器只限于表表名:触发器只限于表

Page 84: 第14章  PL/SQL 语言基础

触发器体是触发器体是 PL/SQLPL/SQL 块,但不能用事务命令,不块,但不能用事务命令,不能有能有 LONGLONG 或或 LONG RAWLONG RAW 变量。变量。

当对表进行当对表进行 IDUIDU操作时,要立即执行某些动作时操作时,要立即执行某些动作时就可定义触发器。就可定义触发器。

例例 11 :: CREATE OR REPLACE TRIGGER TTCREATE OR REPLACE TRIGGER TT BEFORE DELETE OR UPDATEBEFORE DELETE OR UPDATE OR INSERT ON EMPLOYEESOR INSERT ON EMPLOYEES BEGINBEGIN DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT.PUT_LINE(' 触发器触发器 TT');TT'); END;END;

执行执行:: UPDATE EMPLOYEES SET SALARY=UPDATE EMPLOYEES SET SALARY= SALARY+100 WHERE SALARY<=10000;SALARY+100 WHERE SALARY<=10000;

触发器触发器 TT TT ---- 表示触发器执行表示触发器执行

Page 85: 第14章  PL/SQL 语言基础

例例 22: : 行级触发器行级触发器 CREATE OR REPLACE TRIGGER TT1CREATE OR REPLACE TRIGGER TT1 BEFORE DELETE OR UPDATEBEFORE DELETE OR UPDATE OR INSERT ON EMPLOYEESOR INSERT ON EMPLOYEES FOR EACH ROWFOR EACH ROW WHEN WHEN (OLD.SALARY>=10000) –(OLD.SALARY>=10000) – 必须括号必须括号 BEGINBEGIN DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT.PUT_LINE(' 触发器触发器 TT1');TT1'); END;END;DELETE FROM EMPLOYEES WHERE SALAYR DELETE FROM EMPLOYEES WHERE SALAYR

>=11111; >=11111; ----删除记录的删除记录的 SALARY>=10000SALARY>=10000,, 触发一次触发一次

Page 86: 第14章  PL/SQL 语言基础

2. 2. OLDOLD 和和 NEWNEW 触发器中的“触发器中的“ :OLD.:OLD. 列名”列名”和“和“ :NEW.:NEW. 列名”列名”OLD:OLD: 操作之前值,对操作之前值,对 UPDATEUPDATE 和和 DELETEDELETENEWNEW ::新值,只对新值,只对 UPDATEUPDATE 和和 INSERTINSERT create or replace trigger empcreate or replace trigger emp before update on employeesbefore update on employees for each rowfor each row declare --declare -- 说明部分说明部分 v1 number;v1 number; v2 number;v2 number; beginbegin v1:=v1:=:old.salary:old.salary;; v2:=v2:=:new.salary:new.salary;; dbms_output.put_line('old:'||to_char(v1)||' new:'||to_char(v2));dbms_output.put_line('old:'||to_char(v1)||' new:'||to_char(v2));

end;end;执行:执行: update employees set salary=salary+1000 update employees set salary=salary+1000

where salary>=10000;where salary>=10000;

Page 87: 第14章  PL/SQL 语言基础

3. 3. 触发器谓词触发器谓词INSERTING: INSERTING: 触发语句是触发语句是 INSERT,INSERT, 取值取值 TRUETRUEUPDATING: UPDATING: 触发语句是触发语句是 UPDATE,UPDATE, 取值取值 TRUETRUEDELETING: DELETING: 触发语句是触发语句是 DELETE,DELETE, 取值取值 TRUETRUE例例 44 :: create or replace trigger ttt2create or replace trigger ttt2 before delete or update or insert before delete or update or insert on employees for each rowon employees for each rowbeginbegin if inserting thenif inserting then dbms_output.put_line('insertdbms_output.put_line('insert 触发器触发器 ');'); end if;end if; if updating thenif updating then dbms_output.put_line('updatedbms_output.put_line('update 触发器触发器 ');'); end if;end if; if deleting thenif deleting then dbms_output.put_line('deletedbms_output.put_line('delete 触发器触发器 ');'); end if;end if; end;end;

Page 88: 第14章  PL/SQL 语言基础

4.4. 删除和禁止触发器删除和禁止触发器DROP TRIGGER DROP TRIGGER 触发器名触发器名ALTER TRIGGER ALTER TRIGGER 触发器名 触发器名 [[DISABLE|DISABLE|

ENABLE]ENABLE]

ALTER TABLE ALTER TABLE 表名 表名 ENABLE ALL TRIGGERSENABLE ALL TRIGGERS

激活“表名”的所有触发器激活“表名”的所有触发器ALTER TABLE ALTER TABLE 表名 表名 DISABLE ALL TRIGGERSDISABLE ALL TRIGGERS

5. 5. 查询触发器查询触发器 ((USER_TRIGGERS)USER_TRIGGERS)

TIRGGER_NAME TRIGGER_TYPETIRGGER_NAME TRIGGER_TYPE

TRIGGERING_EVENTTRIGGERING_EVENT

TABLE_OWNER TABLE_NAMETABLE_OWNER TABLE_NAME

WHEN_CLAUSE TRIGGER_BODYWHEN_CLAUSE TRIGGER_BODY

Page 89: 第14章  PL/SQL 语言基础

六、异常处理六、异常处理运行中出现的错误,异常处理将捕获错误。运行中出现的错误,异常处理将捕获错误。1.1. 系统预定义异常系统预定义异常

异常号异常号 异常关键字异常关键字 说明说明ORA_1001ORA_1001 INVALID_CURSORINVALID_CURSOR 非法游标操作非法游标操作ORA_1012ORA_1012 NOT_LOGGED_ONNOT_LOGGED_ON 没连接到没连接到 oracleoracle

ORA_1403ORA_1403 NOT_DATA_FOUNDNOT_DATA_FOUND 没有找到数据没有找到数据ORA_1722ORA_1722 INVALID_NUMBERINVALID_NUMBER 转换数字时失败转换数字时失败ORA_6500ORA_6500 STOREAGE_ERRORSTOREAGE_ERROR 内存不够内存不够ORA_6501ORA_6501 PROGRAM_ERRORPROGRAM_ERROR 内部内部 PL/SQLPL/SQL 错错

误误ORA_6502ORA_6502 VALUE_ERRORVALUE_ERROR 截尾、算术错误截尾、算术错误ORA_1476ORA_1476 ZERO_DIVIDEZERO_DIVIDE 被零除被零除

Page 90: 第14章  PL/SQL 语言基础

2. 2. 用户定义异常用户定义异常 异常名 异常名 EXCEPTION;EXCEPTION; 在说明部分在说明部分 ((DECLAREDECLARE 后后 )) 定义异常。定义异常。 ERR1 EXCEPTIONERR1 EXCEPTION ;; 触发异常:触发异常: RAISE RAISE 异常名异常名 ;;3. 3. 异常处理异常处理 EXCEPTIONEXCEPTION WHEN WHEN 异常名异常名 1 1 THENTHEN 语句序列语句序列 11 ;; … … WHEN WHEN 异常名异常名 N THENN THEN 语句序列语句序列 NN WHEN WHEN OTHERS OTHERS THENTHEN 语句序列语句序列 N+1N+1 ;;

Page 91: 第14章  PL/SQL 语言基础

例例 11 ::异常实例异常实例DeclareDeclare a int:=0;a int:=0; b int; b int; err1 exception; --err1 exception; -- 异常说明异常说明BeginBegin b:=10/a;b:=10/a; if a=0 thenif a=0 then raise err1;raise err1; end if;end if; exception exception when zero_divide thenwhen zero_divide then dbms_output.put_line(‘dbms_output.put_line(‘ 被被 00 除’除’ );); when err1 thenwhen err1 then dbms_output.put_line(‘Adbms_output.put_line(‘A 为零’为零’ ););end;end;

Page 92: 第14章  PL/SQL 语言基础

七、动态七、动态 PL/SQLPL/SQL

需要动态需要动态 SQLSQL 的情况:的情况:要执行要执行 SQLSQL 中的数据定义语句、权限语句和佳话中的数据定义语句、权限语句和佳话

控制语句控制语句更大的灵活性,动态生成更大的灵活性,动态生成 SQLSQL 语句等语句等用包用包 DBMS_SQLDBMS_SQL 来执行来执行 SQLSQL 动态动态EXECUTE IMMEDIATE EXECUTE IMMEDIATE 动态串动态串 [[USING USING 变量名表变量名表 ]] ;;

动态串是字符串。动态串中有引用变量用“动态串是字符串。动态串中有引用变量用“ :: 标识标识符符””

或“或“ :1,:2:1,:2”” ,此时标识符不需要说明,但必须用子,此时标识符不需要说明,但必须用子句句

USING USING 为它们赋值。为它们赋值。

Page 93: 第14章  PL/SQL 语言基础

例 1 :动态 SQLdeclare sql_stmt varchar2(200); plsql_block varchar2(500); emp_id number(4) := 7566; salary number(7,2); dept_id number(2) := 50; dept_name varchar2(14) := 'personnel'; location varchar2(13) := 'dallas'; emp_rec emp%rowtype;begin execute immediate 'create table bonus (id

number, amt number)'; --建立表 sql_stmt := 'insert into dept values (:1, :2, :3)';

Page 94: 第14章  PL/SQL 语言基础

execute immediate sql_stmt using dept_id, dept_name, location;

sql_stmt :='select * from emp where employee_id = :id';

execute immediate sql_stmt using emp_id; plsql_block := 'begin

dbms_output.put_line(to_char(:NN)); end;'; execute immediate plsql_block using 'DDD'; sql_stmt := 'update emp set salary = 2000 where

employee_id = :1'; execute immediate sql_stmt using emp_id ; execute immediate 'delete from dept where

department_id = :num' using dept_id;end;

Page 95: 第14章  PL/SQL 语言基础

例例 22 :存储过程中用动态:存储过程中用动态 SQLSQLcreate or replace procedure create or replace procedure delete_rows delete_rows ((table_name in varchar2,table_name in varchar2,

condition in varchar2 default nullcondition in varchar2 default null) ) asas

where_clause varchar2(100) :=' where_clause varchar2(100) :=' where '|| condition;where '|| condition;

beginbegin if condition is null thenif condition is null then where_clause := null;where_clause := null; end if;end if; execute immediateexecute immediate 'delete from ' || 'delete from ' || table_name || where_clause;table_name || where_clause;

end;end;

Page 96: 第14章  PL/SQL 语言基础

调用过程:调用过程:beginbegin

delete_rows('JOBS','MIN_SALARY>=5000');delete_rows('JOBS','MIN_SALARY>=5000');

dbms_output.put_line(to_char(sql%rowcount));dbms_output.put_line(to_char(sql%rowcount));

end;end;

Page 97: 第14章  PL/SQL 语言基础

例例 33 :建立用户:建立用户declaredeclare n number(1);n number(1); sn varchar2(8);sn varchar2(8); sn1 char(3);sn1 char(3);beginbegin for n in 111..222 loopfor n in 111..222 loop sn1:=ltrim(to_char(n,'999'));sn1:=ltrim(to_char(n,'999')); sn:=rtrim('swj'||sn1); sn:=rtrim('swj'||sn1); execute immediate 'create user '||sn||' execute immediate 'create user '||sn||' identified by swj default tablespace swj identified by swj default tablespace swj quota unlimited on swj';quota unlimited on swj'; execute immediate 'grant swjrole to '||sn;execute immediate 'grant swjrole to '||sn; end loop;end loop;end;end;

Page 98: 第14章  PL/SQL 语言基础

上机内容:上机内容:1.1. 编写判定一个四位数是否为回文数的函数,并统编写判定一个四位数是否为回文数的函数,并统

计出所有四位数中的回文数。计出所有四位数中的回文数。 ((正读正读 ==反读反读 ))2.2. 编写从表编写从表 JOBSJOBS删除第删除第 NN 条记录的过程。条记录的过程。3.3. 编写过程:当给定的编写过程:当给定的 JOB_IDJOB_ID 存在时,显示该记存在时,显示该记

录的内容,如果不存在则将该录的内容,如果不存在则将该 JOB_IDJOB_ID 以记录以记录((JOB_ID,’NET JOB’,1000,10000)JOB_ID,’NET JOB’,1000,10000) 插入插入 JOBSJOBS 。。

4.4. 编写函数:对编写函数:对 EMPLOYEESEMPLOYEES 按工资从小到大排按工资从小到大排序后的第序后的第 MM 条到第条到第 NN 条记录的工资总和。条记录的工资总和。

5.5. 编写函数:给定员工编号,返回该员工所在部门编写函数:给定员工编号,返回该员工所在部门的名称。如果没有找到,返回的名称。如果没有找到,返回 NULLNULL 。。

6.6. 编写过程:对给定工作编号,如果找到返回它的编写过程:对给定工作编号,如果找到返回它的最小和最大工资;如果没有找到将该编号插入,最小和最大工资;如果没有找到将该编号插入,工作名称为工作名称为 OFFICEROFFICER ,,最小工资为最小工资为 JOBSJOBS

Page 99: 第14章  PL/SQL 语言基础

中所有记录最小工资的平均值,最大值为原最大中所有记录最小工资的平均值,最大值为原最大值的平均值。值的平均值。7. 7. 编写过程:从表编写过程:从表 JOBSJOBS 中删除按工作编号从小中删除按工作编号从小

到大排序后第到大排序后第 NN 条记录。条记录。8. 8. 编写过程:输入一个字符串,判定否是可以作编写过程:输入一个字符串,判定否是可以作

为用户名,显示异常。如果可以建立该用户,并为用户名,显示异常。如果可以建立该用户,并为其授予为其授予 create session,create table,select any create session,create table,select any table table 权限。权限。

9. 9. 建立一个包:定义求建立一个包:定义求 N!N! 的函数和显示表的函数和显示表 JOBSJOBS记录个数的过程。记录个数的过程。

10. 10. 定义触发器:对表定义触发器:对表 EMPLOYESSEMPLOYESS 建立插入、建立插入、删除、修改之前分别显示:开始插入、开始删除、删除、修改之前分别显示:开始插入、开始删除、开始修改。开始修改。