5. PL/SQL
PL/SQL(Procedural Language/SQL)是在标准SQL的基上增加了q程化处理的语言
Oracle客户端工兯问Oracle服务器的操作语言
Oracle对SQL的扩?br /> BEGIN
IF TO_CHAR(SYSDATE, 'DAY')='Monday' THEN
pay_for_hamburgers;
ELSE
borrow_hamburger_money;
END IF;
END;
6. PL/SQL
l构化模块化~程
良好的可UL?br /> 良好的可l护?br /> 提升pȝ性能
不便于向异构数据库移植应用程?br />
7. SQL
W四代语a
做什么,不管怎么?br /> ~少q程与控制语?br /> 无算法描q能?br />
8. PL/SQL
Procedural Language/SQL
扩展
-变量和类?br /> -控制l构
-q程与函?br /> -对象cd与方?br /> BEGIN
IF TO_CHAR(SYSDATE, 'DAY')='Monday' THEN
pay_for_hamburgers;
ELSE
borrow_hamburger_money;
END IF;
END;
9. W二?br /> 1.PL/SQL?br /> 2. PL/SQLE序l构
3. 变量与数据类型 ?br /> 4. PL/SQL控制语句
5. PL/SQL游标
6. 异常捕获
7. 子程?br /> 1. q程
2. 函数
8. ?br /> 9. 触发?
10. PL/SQLE序l构
PL/SQL?br /> -x部分Q?DECLARE
-执行部分Q?BEGIN
-异常处理Q?EXCEPTION
DECLARE
v_StudentID NUMBER(5):=1000;
v_FirstName VARCHAR(20);
BEGIN
SELECT first_name
INTO v_FirstName
FROM students
WHERE id=v_StudentID;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_table(info)
VALUES('Student 1000 does not exist!');
END;
11. PL/SQL开发环?br /> SqlPlus▲工?br /> GUI开发工?br /> -SQL游览?br /> -SQLE序?br /> …?br /> 相关信息
http://www.oracle.com
http://gwynne.cs.ualberta.ca/~oracle/817doc/index.htm
注:?Oracle公司的SQL工具Q也可以用它来操作Oracle数据库?/p>
12. PL/SQL字符?br /> 字母QA-Z, a-z
数字Q?-9
I白QTab,I格Q回?br /> W号Q?-*/<>=();:'@"%||&--/**/
PL/SQL对大写不敏?/p>
13. 标识W?br /> 用来l对象命?br /> -变量、游标、类型、子E序
命名规则
-字母开?br /> -后跟L的非I格字符、数字、货币符受下划线?
-最大长度ؓ30个字W?br /> 标识W的例子
x, First Name, v_StudentID, x+y, TempVar, _tmp_, v1, v2_,
1_var, s#, v$3, This_is_a_really_long_identifier
14. 变量声明
语法
变量?cd [常数] [非空] [:=值];
例子
DECLARE
v_Desc VARCHAR2(50);
v_Num NUMBER:=45;
v_Count BINARY_INTEGER:=0;
PL/SQL规定没有初始化的变量为NULL
-NULLQ未定义
15. W三?br /> 1.PL/SQL?br /> 2. PL/SQLE序l构
3. 变量与数据类型 ?br /> 4. PL/SQL控制语句
5. PL/SQL游标
6. 异常捕获
7. 子程?br /> 1. q程
2. 函数
8. ?br /> 9. 触发?
16. 数据cd
标量?br /> -数字型、字W型、布型、日期型
l合?br /> -RECORD, TABLE, VARRAY
参考型
-REF CURSOR, REF object_type
LOB(大对?
-BFILE 是二q制Q存储在数据库外面的
-BLOB 是二q制
-CLOB 是单字节字符数据
-NCLOB 是多字节字符数据
17. 标量cd
数字cd
-BINARY_INTEGER, DEC, FLOAT, REAL...
-NUMBER
-NUMBER(3)
-NUMBER(4,3)
-How about NUMBER(4,6)
字符?br /> -CHAR, VARCHAR, VARCHAR2, STRING...
-LONG
布尔?BOOLEAN)
日期?DATE)
18. %TYPE
变量h与数据库的表中某一字段相同的类?br /> DECLARE
v_FirstName VARCHAR2(20);
DECLARE
v_FirstName students.first_name%TYPE;
19. 记录cd
TYPE 记录?IS RECORD(
? cd1 [非空] [:=表达?]
? cd2 [非空] [:=表达?]
...
域n cdn [非空] [:=表达式n]
如果一个字D限定NOT NULLQ那么它必须拥有一个初始?br /> 所有没有初始化的字D都会初始化为NULL
20. RECORDcd的?br /> DECLARE
TYPE t_Rec IS RECORD(
student_id NUMBER(4),
first_name VARCHAR2(20):='Scott',
last_name VARCHAR2(20),
major BINARY_INTEGER);
v_Stu t_Rec;
同类型的RECORD变量可以怺赋?br /> 按RECORD变量的字D赋?记录?域名)
21. %ROWTYPE
%ROWTYPEq回一个基于数据库表定义的cd
DECLARE
v_StuRec Student%ROWTYPE;
...
v_StuRec.student_id := 1234;
v_StuRec.first_name := 'Bush';
...
%ROwtype和record的区别是什么?
22. TABLEcd
TYPE 表类?IS TABLE OF cd INDEX BY BINARY_INTEGER;
TABLEcd与map<int, _T>cM
表中元素的类型可以是复合cd
行的数目的限制由BINARY_INTEGER的范围决?br /> Key没有必要是顺序的
当数据被插入表中Ӟ表所需的空间就被分配了
23. TABLEcd的例?br /> DECLARE
TYPE t_StuTable IS TABLE OF Student%ROWTYPE INDEX BY BINARY_INTEGER;
v_Student t_StuTable;
BEGIN
SELECT *
INTO v_Student(1001)
FROM Student
WHERE id = 1001;
END;
24. 变量的作用域与可见?br /> DECLARE
v_Num NUMBER(3, 2);
BEGIN
v_Num := 123.45;
DECLARE
v_Ch VARCHAR2(10);
BEGIN
v_Num := 321.45;
v_Ch := 'Hello';
...
END;
...
END;
25. W四?br /> 1.PL/SQL?br /> 2. PL/SQLE序l构
3. 变量与数据类型 ?br /> 4. PL/SQL控制语句
5. PL/SQL游标
6. 异常捕获
7. 子程?br /> 1. q程
2. 函数
8. ?br /> 9. 触发?
26. PL/SQL控制语句
条g语句
循环语句
GOTO语句
注:?在PL/SQL中,--为单行注释,/**/为多行注释。 ?
27. 条g语句
IF THEN ELSE END IF
IF 布尔表达? THEN
...
ELSIF 布尔表达? THEN
...
ELSE
...
END IF;
条g为NULL与FALSE相同
28. 循环语句1
单@?br /> LOOP
...
IF 布尔表达?THEN
EXIT;
END IF;
END LOOP;
29. 循环语句2
WHILE循环
WHILE 布尔表达?LOOP
...
END LOOP;
30. 循环语句3
FOR循环
FOR 循环计数 IN [反向的] 下限..上限 LOOP
...
END LOOP;
31. GOTO语句
GOTO 标签?
只能由内部的语句块蟩往外部?br /> 讄标签
<<标签?gt;>
可以为@环设|标{?br /> ...
<<l_b1>>
FOR v_index IN 1..50 LOOP
...
IF v_index > 40 THEN
EXIT l_b1;
END IF;
END LOOP l_b1;
32. NULL语句
可以在语句块中加I?br /> 用于补充语句的完整?br /> IF v_idx > 40 THEN
...
ELSE
NULL;
END IF;
33. SQL中的PL/SQL 1
数据操纵语言
SELECT, INSERT, DELETE, SET TRANSACTION, EXPLAIN PLAN
数据定义语言
DROP, CREATE, ALTER, GRANT, REVOKE
事务控制
COMMIT, ROLLBACK, SAVEPOINT
会话控制
ALERT SESSION, SET ROLE
pȝ控制
ALERT SYSTEM
ESQL
CONNECT, DECLARE CURSOR, ALLOCATE
34. SQL中的PL/SQL 2
只有DML SQL可以直接在PL/SQL中?br /> 使用Oracle内置的DBMS_SQL包,可以使用动态SQL语句
动态SQL语句是在q行时生成一个SQL的串Q将该串提交lDBMS_SQL包来执行
35. 内置的SQL函数
字符函数
CHR, CONCAT, INITCAP, LOWER, LPAD, LTRIM, RTRIM, REPLACE,
RPAD, SUBSTR, SUBSTRB, TRANSLATE UPPER, INSTR, ASCII,LENGTH...
数字函数
ABS, ACOS, ASIN, CEIL, EXP, FLOOR, LOG, MOD, POWER, ROUND...
日期函数
ADD_MONTHS, LAST_DAY, MONTHS_BETWEEN, NEW_TIME, NEXT_DAY, ROUND, SYSDATE, TRUNC...
转换函数
CHARTOROWID, CONVERT,HEXTORAW, RAWTOHEX, ROWIDTOCHAR, TO_CHAR, TO_DATE, COUNT...
36. W五?br /> 1.PL/SQL?br /> 2. PL/SQLE序l构
3. 变量与数据类型 ?br /> 4. PL/SQL控制语句
5. PL/SQL游标
6. 异常捕获
7. 子程?br /> 1. q程
2. 函数
8. ?br /> 9. 触发?br />
37. 游标
游标用于提取多行数据?br /> 游标的?br /> -声明游标
-为查询打开游标
-结果提取出来,存入PL/SQL变量?br /> -关闭游标
38. 声明游标
DECLARE CURSOR 游标?IS 选择声明
如果在选择声明中用了PL/SQLQ变量的声明必须攑֜游标前面
v_major students.major%TYPE;
DECLARE
CURSOR c_student IS
SELECT first_name, last_name
FROM students
WHERE major = v_major;
变量名与列名一致但不同
39. 打开游标
OPEN 游标?br /> 若选择声明巜y等待更新”则加锁?/p>
40. 从游标取
FETCH的两UŞ?br /> -FETCH 游标?INTO 变量1, 变量2,...;
-FETCH 游标?INTO 变量记录
41. 关闭游标
CLOSE 游标?
游标使用后应该关?br /> -FETCH关闭后的游标是非法的
-关闭一个关闭了的游标也是非法的
42. 游标的属?br /> %FOUND
%NOTFOUND
%ISOPEN
%ROWCOUNT
43. 游标的FETCH循环
LOOP
FETCH 游标 INTO...
EXIT WHEN 游标%NOTFOUND;
END LOOP;
WHILE 游标%FOUND LOOP
44. 游标的例?br /> Mycursor:
print name and id from student where age < 30
For_cursor:
Print dept_id, user_id, last_name, first_name from s_emp
where dept_id < 40
45. 带参数的游标
CURSOR可以带参?br /> DECLARE
CURSOR c_student(p_major students.major%TYPE)
SELECT *
FROM students
WHERE major = p_major;
BEGIN
OPEN c_student(101);
...
46. W六?br /> 1.PL/SQL?br /> 2. PL/SQLE序l构
3. 变量与数据类型 ?br /> 4. PL/SQL控制语句
5. PL/SQL游标
6. 异常捕获
7. 子程?br /> 1. q程
2. 函数
8. ?br /> 9. 触发器 ?br />
47. 异常
PL/SQL错误
-~译?br /> -q行?br /> q行时的出错处理
-EXCEPTION
48. 异常处理?br /> DECLARE
...
BEGIN
...
EXCEPTION
WHEN OTHERS THEN
handler_error(...);
END;
49. 用户自定义的异常
DECLARE
e_TooManyStudents EXCEPTION;
BEGIN
...
RAISE e_TooManyStudents;
...
EXCEPTION
WHEN e_TooManyStudents THEN
...
END;
50. 预定义的ORACLE异常
ORA-0001
-DUP_VAL_ON_INDEX
ORA-0051
-TIMEOUT_ON_RESOURCE
ORA-1001
-INVALID_CURSOR
...
ORA-6533
-SUBSCRIPT_BEYOND_COUNT
51. 触发异常
RAISE exception_variable
DECLARE
A EXCEPTION
BEGIN
...
RAISE A;
...
EXCEPTION
WHEN A THEN
...
END;
52. 处理异常
EXCEPTION
WHEN e_TooManyStudents THEN
INSERT INTO log_file(info)
VALUES('Major 1100 has' || v_CurStudents || 'max aloowed is' || v_Max);
END;
53. 处理所有的异常
异常的传?br /> 处理所有其他异?br /> EXCEPTION
WHEN e_TooManyStudents THEN
...
WHEN OTHERS THEN
v_ErrCode := SQLCODE;
v_ErrText := SUBSTR(SQLERRM, 1, 200);
INSERT INTO log_file(code, message, info)
VALUES(v_ErrCode, v_ErrCode, v_ErrText, 'ORACLE Error');
END;
54. W七?br /> 1.PL/SQL?br /> 2. PL/SQLE序l构
3. 变量与数据类型 ?br /> 4. PL/SQL控制语句
5. PL/SQL游标
6. 异常捕获
7. 子程?br /> 1. q程
2. 函数
8. ?br /> 9. 触发器 ?br />
55. 子程?br /> 匿名?br /> -匿名块不存在于数据库?br /> -每次使用旉会进行编?br /> -不能在其他块中相互调?br /> 带名?br /> -可存储于数据库中
-可以在Q何需要的地方调用
-q程、函数、包、触发器
56. q程
创徏procedure
CREATE [OR REPLACE] PROCEDURE proc_name
[(arg_name[{IN | OUT | IN OUT}]TYPE,
...
arg_name[{IN | OUT | IN OUT}]TYPE)]
{IS | AS}
procedure_body
57. q程的参数模?br /> IN
-在调用过E的时候,实际参数的D传递给该过E;在过E内部,形参是只可读的?br /> OUT
-在调用过E时QQ何的实参被忽略Q在q程内部QŞ参是只可写的?br /> IN OUT
-是IN与OUT 的组合,在调用过E的时候,实参的值可以被传递给该过E;在过E内部,形参也可以被d也可以被写入Q?br /> q程l束Ӟ控制会返回给控制环境Q而Ş式参数的内容赋l调用时的实际参数?br /> 参数的缺省模式是IN
58. q程的主?br /> PROCEDURE BODY
-q程的主体是一个拥有声明,执行和异常处理的完整的PL/SQL块 ?br /> -声明部分在IS或AS关键字与BEGIN关键字之?br /> -执行部分在BEGIN和EXCEPTION之间
-异常处理在EXCEPTION与END之间
59. q程的例子 ?br /> CREATE OR REPLACE PROCEDURE ModeText(
p_InParm IN NUMBER,
p_OutParm OUT NUMBER,
p_InOut IN OUT NUMBER)
IS
v_LocalVar NUMBER;
BEGIN
v_LocalVar := p_InParm; //legal
p_InParm := 7; //illegal
p_OutParm := 7; //legal
v_LocalVar := p_OutParm; //illegal
v_LocalVar := p_InOutParm; //legal
p_InOutParm := 7; //legal
...
END ModeTest;
60. 调用q程的例?br /> DECLARE
v_var1 NUMBER := 1001;
v_var2 NUMBER := 1234;
BEGIN
ModeTest(10, v_var1, v_var2);
END;
DECLARE
v_var1 NUMBER;
BEGIN
ModeTest(12, v_var1, 10);
END;
61. 指定实参的模?br /> 位置标示?br /> -调用时添入所有参敎ͼ实参与Ş参按序一一对应
名字标示?br /> -调用时给出Ş参名字,q给出实?br /> ModeTest(p_InParm => 12,
p_OutParm => v_var1,
p_InOut => 10);
两种Ҏ可以L
-LӞW一个参数必通过位置来指?br /> -名字标示法对于参数很多时Q可提高E序的可L?br />
62. 使用~省参数?br /> 形参可以指明~省?br /> parm_name[mode]type{:= | DEFAULT} init_value
位置标示法时Q所有的~省值都攑֜最后面
-使用名字标示法则无所?br /> 如果使用了缺省|量缺省值放在参数表的末?br />
63. 函数
函数在所有的地方都与q程怼
-都有名字
-都有l一的Ş式:声明、执行与异常处理
-可以存储在数据库中,也可以声明在无名块的内部
差别
-q程调用本n是一个PL/SQL语句
-函数调用是表辑ּ的一部分
注:?另外Q函数有q回|而过E没有?br />
64. 函数的声?br /> CREATE [OR REPLACE] FUNCTION func_name
[(arg_name[{IN | OUT | IN OUT}]TYPE,
...
arg_name[{IN | OUT | IN OUT}]TYPE)]
RETURN TYPE
{IS | AS}
function_Body
65. RETURN语句
在函数的M内部Qreturn语句用来控刉过一个数D回给调用环境
- RETURN <表达?gt;;
在一个函C体中Q可以用多个返回语?br /> 没有q回语句的函数将是一个错?br />
66. 函数样式
函数可以通过OUT参数来返回多个数?br /> 函数可以接收~省参数
67. 删除q程与函?br /> DROP PROCEDURE procedure_name;
DROP FUNCTION function_name;
68. 子程序的位置
存储子程?br /> -通过CREATE OR REPLACE命o创徏
-以编译后的Ş式存攑֜数据库中
本地子程?br /> -没有CREATE OR REPLACE关键?br /> -子程序的定义攑֜无名块的声明部分
-子程序被该无名块使用
69. 本地子程?br /> DECLARE
v_var VARCHAR2;
FUNCTION func(p_Fname IN VARCHAR2, p_Lname IN VARCHAR2)
RETURN VARCHAR2 IS
BEGIN
...
END func;
BEGIN
v_var := func('First Name', 'Last Name');
...
END;
70. W八?br /> 1.PL/SQL?br /> 2. PL/SQLE序l构
3. 变量与数据类型 ?br /> 4. PL/SQL控制语句
5. PL/SQL游标
6. 异常捕获
7. 子程?br /> 1. q程
2. 函数
8. ?br /> 9. 触发?br />
71. ?br /> 包是可以相兛_象存储在一LPL/SQLl构
包只能存储在数据库中Q不能是本地的?br /> 包是一个带有名字的声明
相当于一个PL/SQL块的声明部分
在块的声明部分出现的M东西都能出现在包?br /> 包中可以包含q程、函数、游标与变量
可以从其他PL/SQL块中引用包,包提供了可用于PL/SQL的全局变量
72. 包规范 ?br /> 包头Q包含了有关包的内容的信?br /> 包头不含Mq程的代?br /> 包规范的语法
CREATE [OR REPLACE] PACKAGE pack_name{IS | AS}
procedure_specification | function_specification |
variable_declaration | type_definition |
exception_declaration | cursor_declaration
END pack_name;
73. 包头的例?
CREAE OR REPLACE PACKAGE pak_test AS
PROCEDURE AddStudent(p_StuID IN students.id%TYPE,
p_Dep IN classes.department%TYPE,
p_Course IN classes.course%TYPE);
PROCEDURE RemoveStudent(p_StuID IN students.id%TYPE);
e_StudentNotRegistered EXCEPTION;
TYPE t_StuIDTable IS TABLE OF students.id%TYPE INDEX
BY BINARY_INTEGER;
END pak_name;
74. 包头的例?
在包pak_test中包含了两个q程Q一个类型与一个异?br /> AddStudent
RemoveStudent
t_StuIDTable
e_StudentNotRegistered
包的部g可以按Q意次序出玎ͼ但对象必d明在被引用的前面
所有过E或函数的代码不能出现在包头?br />
75. 包主体 ?br /> 包主体是可选的Q如果包头中没有M函数与过E,则包M可以不需?br /> 包主体与包头存放在不同的数据字典?br /> 如果包头的编译不成功Q包M无法正的~译出来
包主体中包含了在包头中声明的所有过E与函数的代?br /> q程与函数的规范在包头与包主体中必须一?br /> 规范包括子程序的名字Q参数的名字以及参数的模式:包括cd与顺?br />
76. 包主体的语法
CREATE OR REPLACE PACKAGE BODY pak_test AS
PROCEDURE AddStudent(p_StuID IN students.id%TYPE,
p_Dep IN classes.department%TYPE,
p_Course IN classes.course%TYPE) IS
BEGIN
...
END AddStudent;
PROCEDURE RemoveStudent(p_StuID IN students.id%TYPE) IS
BEGIN
...
END RemoveStudent;
END pak_test;
77. 包的作用?br /> 在包头中声明的所有东西在包的外面都可以?br /> 使用时必L明包的名?br /> 直接调用包中的过E?br /> pak_test.AddStudent(100010, 'CS', 101);
在包的主体中可以直接使用包头中声明的对象
不需要指明包的名?br />
78. 包中子程序的重蝲
同一个包中的q程与函数都可以重蝲
相同的过E或函数名字Q但参数不同
重蝲不能仅仅依据是参数名字和模式不同
重蝲不能仅仅依据函数的返回类?br /> 重蝲的参数必L不同cd?br /> 重蝲要求参数cd必须不同
而且要求是不同类型族?br /> 无法区分CHAR与VARCHAR2
79. 包的初始?br /> 包存攑֜数据库中
在第一ơ被调用的时候,包从数据库中调入内存q被初始?br /> 包中定义的所有变量都被分配内?br /> 每个会话都将拥有自己的包内变量的副本
可以指定包的初始化代?br /> CREATE OR REPLACE PACKAGE BODY pac_name{IS | AS}
...
BEGIN
--Initialization code
END pac_name;
80. W九?br /> 1.PL/SQL?br /> 2. PL/SQLE序l构
3. 变量与数据类型 ?br /> 4. PL/SQL控制语句
5. PL/SQL游标
6. 异常捕获
7. 子程?br /> 1. q程
2. 函数
8. ?br /> 9. 触发?
81. 触发?br /> 触发器与q程、函数类?br /> 都是带有名字的执行块
都有声明、执行体和异常处理部?br /> 触发器与q程、函数的差别
触发器必d储在数据库中
对于q程和函敎ͼ必须昑ּ地由另一个运行块调用
对于触发器,是由触发事g自动Ȁ?br /> 触发事g是在数据库表上执行的DML数据操作
INSERT, UPDATE, DELETE
82. 触发器的作用
用于l护数据的完整?br /> 有些复杂的数据完整性约束无法在创徏表的时刻通过声明性约束解?br /> 通过数据库表的记录的修改来执行审计功?br /> 当表被修改的时候,自动l其他需要执行操作的E序发信?br />
83. 创徏触发?br /> 语法
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER} triggering_event ON table_reference
[FOR EACH ROW[WHEN trigger_condition]]
trigger_body;
必须的部?br /> 触发器名Qtrigger_name
触发事gQtriggering_event
触发器主体:trigger_body
可选部?br /> WHEN子句
84. 触发器的例子
CREATE OR REPLACE TRIGGER UpdateMajorStats
AFTER INSERT OR DELETE OR UPDATE ON students
DECLARE
CURSOR c_Statistics IS
SELECT major, COUNT(*) total_students, SUM(current_credits) total_credits
FROM students
GROUP BY major;
BEGIN
FOR v_StatsRecord in c_Statistics LOOP
UPDATE major_stats
SET total_credits = v_StatsRecord.total_credits,
total_students = v_StatsRecord.total_students
WHERE major = v_StatsRecord.major;
IF SQL%NOTFOUND THEN
INSERT INTO major_stats(major, total_credits, total_students)
VALUES(v_StatsRecord.major, v_StatsRecord.total_credits, v_StatsRecord.total_students);
END IF;
END LOOP;
END UpdateMajorStats;
85. 触发器组?br /> 触发器名
-在同一个数据库?br /> q程、包与表的名字空间相?br /> 触发器用单独的名字I间
触发器可以与表同?br /> 触发器类?br /> -触发事g军_了触发器的类?br /> 语句QINSERT, UPDATE, DELETE
定时QBEFORE, AFTER
U别Q?br /> -行触发?FOR EACH ROW)Q对p发语句媄响的每一行点火一?br /> -语句U触发器Q仅在语句执行前/后执行一?br />
86. 触发器类?br /> 共有12U触发器cd
三个语句(INSERT/UPDATE/DELETE)
两种cd(之前/之后)
两种U别(row-level/statement-level)
一个表最多可以定?2个触发器
PL/SQL2.1以后版本Q对于每U类型可以拥有多个触发器
87. 触发器的限制
触发器的M是PL/SQL语句?br /> 所有能出现在PL/SQL块中的语句在触发器主体中都是合法的限?br /> 不应该用事务控制语?br /> COMMIT, ROLLBACK, SAVEPOINT
p发器调用的Q何过E与函数都不能用事务控制语?br /> 不能声明MLONG或LONG RAW变量
可以讉K的表有限
88. 触发器的M可以讉K的表
变化?br /> 被DML语句正在修改的表Q亦卛_义触发器的表
限制?br /> 有些表在创徏的时候就带有参考完整性限制的声明
主键与外?br /> 触发器主体中的限?br /> 不可以读取或修改M变化?br /> 不可以读取或修改限制表的主键Q唯一值列Q外键列
89. 相关信息
ORACLE产品与资料信?br /> http://www.oracle.com
ORACLE 8i的资?br /> http://gwynne.cs.ualberta.ca/~oracle/817doc/index.htm
90. 学籍理信息?br /> 设计一个data schema, tarena公司的学c管理信息徏立在数据库中
应该包括下列信息
学员信息
评信息
班信息
...
建立数据库表或相兌?br /> 使用sqlplus?使用PL/SQL?
使用PL/SQLE序来完?br /> 输入部分数据
完成单查询功?br /> 使用Pro*C完成下列功能
数据插入、修改与删除
数据查询
91. pȝ使用记费pȝ
思考ƈ设计记帐pȝ中用的data schema
92. 谢谢
★好书推荐:
Oracle9i PL/SQLE序设计(Oracle9i PL/SQL Programming)
Oracle Express出品Q官斏V权威,U承了麦格劳希尔一贯的严}d的作风,而且两位译者翻译也很到?br />
Oracle9i开发指南:PL/SQLE序设计(Oracle9i Developer: PL/SQL Programming)
该书提供了大量宝늚实际l习ZQ包括逐步操作的指g及每一章中的复习题、课外作业以及实例研I?br />
PL/SQL数据库编E??
W一?/p>
1. Oracle应用~辑Ҏ概览
{:1) Pro*C/C++/... : C语言和数据库打交道的ҎQ比OCI更常?
2) ODBC
3) OCI: C语言和数据库打交道的ҎQ和ProC很相|更底层,很少?
4) SQLJ: 很新的一U用Java讉KOracle数据库的ҎQ会的h不多;
5) JDBC
6) PL/SQL: 存储在数据内q行, 其他Ҏ为在数据库外Ҏ据库讉K;
2. PL/SQL
{:1) PL/SQL(Procedual language/SQL)是在标准SQL的基上增加了q程化处理的语言;
2) Oracle客户端工兯问Oracle服务器的操作语言;
3) Oracle对SQL的扩?
4. PL/SQL的优~点
{:优点Q?br /> 1) l构化模块化~程Q不是面向对?
2) 良好的可UL?不管Oracleq行在何U操作系l?;
3) 良好的可l护?~译通过后存储在数据库里);
4) 提升pȝ性能;
~点
1) 不便于向异构数据库移植应用程?只能用于Oracle);
5. SQL与PL/SQL的区?br />{:SQLQ?) W四代语a(语言);
2) 做什么,不管怎么?
3) ~少q程与控制语?
4) 无算?br /> PL/SQL: 1) 扩展变量和类?
2) 扩展控制l构;
3) 扩展q程与函?
4) 扩展对象cd与方?br />
W二?/p>
PL/SQLE序l构
1. PL/SQL?br />{:1) x部分, DECLARE(不可?;
2) 执行部分, BEGIN...END;
3) 异常处理QEXCEPTION(可以没有);
2. PL/SQL开发环?br />{:可以q用MU文本的~辑器编辑,例如QVI
3. PL/SQL字符?br />{:PL/SQL对大写不敏?/p>
4. 标识W命名规?br />{:1) 字母开?
2) 后跟L的非I格字符、数字、货币符受下划线、或# ;
3) 最大长度ؓ30个字W?八个字符左右最合?;
5. 变量声明
{:语法
Var_name type [CONSTANT][NOT NULL][:=value];
注:1) x时可以有默认g可以没有;
2) 如有[CONSTANT][NOT NULL], 变量一定要有一个初始?
3) 赋D句ؓ?=?
4) 变量可以认ؓ是数据库里一个字D?
5) 规定没有初始化的变量为NULL;
W三?/p>
1. 数据cd
{:1) 标量型:数字型、字W型、布型、日期型;
2) l合型:RECORD(常用)、TABLE(常用)、VARRAY(较少?
3) 参考型QREF CURSOR(游标)、REF object_type
4) LOB(Large Object)
2. %TYPE
{:变量h与数据库的表中某一字段相同的类?br /> 例:v_FirstName studengts.first_name%TYPE;
3. RECORDcd
{:TYPE record_name IS RECORD( /*其中TYPEQISQRECORD为关键字Qrecord_name为变量名U?/
field1 type [NOT NULL][:=expr1], /*每个{h的成员间用逗号分隔*/
field2 type [NOT NULL][:=expr2], /*如果一个字D限定NOT NULLQ那么它必须拥有一个初始?/
... /*所有没有初始化的字D都会初始ؓNULL
fieldn type [NOT NULL][:=exprn]);
4. %ROWTYPE
{:q回一个基于数据库定义的类?br /> DECLARE
v_StuRec Student%ROWTYPE; /*Student的名?/
注:?中定一个record相比Q一步就完成Q?中定义分二步Qa. 所有的成员变量都要x; b. 实例化变?
5. TABLEcd
{:TYPE tabletype IS TABLE OF type INDEX BY BINARY_INTEGER;
例:DECLARE
TYPE t_StuTable IS TABLE OF Student%ROWTYPE INDEX BY BINARY_INTERGER;
v_Student t_StuTable;
BEGIN
SELECT * INTO v_Student(100) FROM Student WHERE id = 1001;
END;
注:1) 行的数目的限制由BINARY_INTEGER的范围决?
6. 变量的作用域和可见?br />{:1) 执行块里可以嵌入执行?
2) 里层执行块的变量对外层不可见;
3) 里层执行块对外层执行块变量的修改会媄响外层块变量的?
W四?/p>
1. 条g语句
{:IF boolean_expression1 THEN
...
ELSIF boolean_expression2 THEN /*注意是ELSIFQ而不是ELSEIF*/
... /*ELSE语句不是必须的,但END IF;是必ȝ*/
ELSE
...
END IF;
2. 循环语句
{:1) Loop
...
IF boolean_expr THEN /* */
EXIT; /* EXIT WHEN boolean_expr */
END IF; /* */
END LOOP;
2) WHILE boolean_expr LOOP
...
END LOOP;
3) FOR loop_counter IN [REVERSE] low_blound..high_bound LOOP
...
END LOOP;
注:a. 加上REVERSE 表示递减Q从l束边界到v始边界,递减步长Z;
b. low_blound 起始边界; high_bound l束边界;
3. GOTO语句
{:GOTO label_name;
1) 只能由内部块跛_外部?
2) 讄标签Q?lt;<label_name>>
3) CZQ?br /> LOOP
...
IF D%ROWCOUNT = 50 THEN
GOTO l_close;
END IF;
...
END LOOP;
<<l_close>>;
...
4. NULL语句
{:在语句块中加I句,用于补充语句的完整性。示例:
IF boolean_expr THEN
...
ELSE
NULL;
END IF;
5. SQL in PL/SQL
{:1) 只有DML SQL可以直接在PL/SQL中?
W五?/p>
1. 游标(CURSOR)
{:1) 作用Q用于提取多行数据集;
2) 声明Qa. 普通申明:DELCARE CURSOR CURSOR_NAME IS select_statement /* CURSOR的内容必L一条查询语?/
b. 带参数申明:DELCARE CURSOR c_stu(p_id student.ID%TYPE) SELECT * FROM student WHERE ID = p_id;
3) 打开游标QOPEN Cursor_name; /*相当于执行select语句Q且把执行结果存入CURSOR;
4) 从游标中取数Qa. FETCH cursor_name INTO var1, var2, ...; /*变量的数量、类型、顺序要和Table中字D一?*/
b. FETCH cursor_name INTO record_var;
注:gCURSOR取出攑օ变量中,每FETCH一ơ取一条记?
5) 关闭游标: CLOSE Cursor_name;
注:a. 游标使用后应该关?
b. 关闭后的游标不能FETCH和再ơCLOSE;
c. 关闭游标相当于将内存中CURSOR的内ҎI?
2. 游标的属?br />{:1) %FOUND: 是否有?
2) %NOTFOUND: 是否没有?
3) %ISOPEN: 是否是打开状?
4) %ROWCOUNT: CURSOR当前的记录号;
3. 游标的FETCH循环
{:1) LOOP
FETCH cursor INTO ...
EXIT WHEN cursor%NOTFOUND; /*当cursor中没记录后退?/
END LOOP;
2) WHILE cursor%FOUND LOOP
FETCH cursor INTO ...
END LOOP;
3) FOR var IN cursor LOOP
FETCH cursor INTO...
END LOOP;
W六?/p>
1. 异常
{:DECLARE
...
e_TooManyStudents EXCEPTION; /* x异常 */
...
BEGIN
...
RAISE e_TooManyStudents; /* 触发异常 */
...
EXCEPTION
WHEN e_TooManyStudents THEN /* 触发异常 */
...
WHEN OTHERS THEN /* 处理所有其他异?*/
...
END;
2004-9-8 星期三 ??/p>
PL/SQL数据库编E??
1. 存储q程(PROCEDURE)
{:创徏q程Q?br /> CREATE [OR REPLACE] PROCEDURE proc_name
[(arg_name[{IN|OUT|IN OUT}]TYPE,
arg_name[{IN|OUT|IN OUT}]TYPE)]
{IS|AS}
procedure_body
1) IN: 表示该参C能被赋?只能位于{号双);
2) OUT:表示该参数只能被赋?只能位于{号左边);
3) IN OUT: 表示该类型既能被赋g能传?
2. 存储q程例子
{:CREATE OR REPLACE PROCEDURE ModeTest(
p_InParm IN NUMBER,
p_OutParm OUT NUMBER,
p_InOutParm IN OUT NUMBER)
IS
v_LocalVar NUMBER; /* 声明部分 */
BEGIN
v_LocalVar:=p_InParm; /* 执行部分 */
p_OutParm:=7;
p_InOutParm:=7;
...
EXCEPTION
... /* 异常处理部分 */
END ModeTest;
3. 调用PROCEDURE的例?br />{:1) 匿名块可以调;
2) 其他PROCDEURE可以调用;
例:
DECLARE
v_var1 NUMBER;
BEGIN
ModeTest(12, v_var1, 10);
END;
注:此时v_var1{于7
4. 指定实参的模?br />{:1) 位置标示法:调用时添入所有参敎ͼ实参与Ş参按序一一对应;
2) 名字标示法:调用时给出Ş参名字,q给出实?br /> ModeTest(p_InParm=>12, p_OutParm=>v_var1, p_Inout=>10);
注:a. 两种Ҏ可以L;
b. L时第一个参数必通过位置来指定?/p>
5. 函数(Function)与过E?Procedure)的区?br />{:1) q程调用本n是一个PL/SQL语句(可以在命令行中通过exec语句直接调用);
2) 函数调用是表辑ּ的一部分;
6. 函数的声?br />{:CREATE [OR REPLACE] PROCEDURE proc_name
[(arg_name[{IN|OUT|IN OUT}]TYPE,
arg_name[{IN|OUT|IN OUT}]TYPE)]
RETURN TYPE
{IS|AS}
procedure_body
注:1) 没有q回语句的函数将是一个错?
7. 删除q程与函?br />{:DROP PROCEDURE proc_name;
DROP FUNCTION func_name;
W八?/p>
1. ?br />{:1) 包是可以相兛_象存储在一LPL/SQL的结?
2) 包只能存储在数据库中Q不能是本地?
3) 包是一个带有名字的声明;
4) 相当于一个PL/SQL块的声明部分;
5) 在块的声明部分出现的M东西都能出现在包?
6) 包中可以包含q程、函数、游标与变量;
7) 可以从其他PL/SQL块中引用包,包提供了可用于PL/SQL的全局变量?br /> 8) 包有包头和包MQ如包头中没有Q何函Cq程Q则包主体可以不需要?/p>
2. 包头
{:1) 包头包含了有兛_的内容的信息Q包头不含Q何过E的代码?br /> 2) 语法Q?br /> CREATE [OR REPLACE] PACKAGE pack_name {IS|AS}
procedure_specification|function_specification|variable_declaration|type_definition|exception_declaration|cursor_declaration
END pack_name;
3) CZQ?br /> CREATE OR REPLACE PACKAGE pak_test AS
PROCEDURE RemoveStudent(p_StuID IN students.id%TYPE);
TYPE t_StuIDTable IS TABLE OF students.id%TYPE INDEX BY BINARY_INTEGER;
END pak_test;
3. 包主?br />{:1) 包主体是可选的Q如包头中没有Q何函Cq程Q则包主体可以不需要?br /> 2) 包主体与包头存放在不同的数据字典中?br /> 3) 如包头编译不成功Q包M无法正确~译?br /> 4) 包主体包含了所有在包头中声明的所有过E与函数的代码?br /> 5) CZQ?br /> CREATE OR REPLACE PACKAGE BODY pak_test AS
PROCEDURE RemoveStudent(p_StuID IN students.id%TYPE) IS
BEGIN
...
END RemoveStudent;
TYPE t_StuIDTable IS TABLE OF students.id%TYPE INDEX BY BINARY_INTEGER;
END pak_test;
4. 包的作用?br />{:1) 在包外调用包中过E?需加包?Qpak_test.AddStudent(100010, 'CS', 101);
2) 在包M中可以直接用包头中声明的对象和q程(不需加包?;
5. 包中子程序的重蝲
{:1) 同一个包中的q程与函数都可以重蝲;
2) 相同的过E或函数名字Q但参数不同;
6. 包的初始?br />{:1) 包存攑֜数据库中;
2) 在第一ơ被调用的时候,包从数据库中调入内存q被初始?
3) 包中定义的所有变量都被分配内?
4) 每个会话都将拥有自己的包内变量的副本?/p>
W九?/p>
1. 触发?br />{:1) 触发器与q程/函数的相同点
a. 都是带有名字的执行块;
b. 都有声明、执行体和异帔R?
2) 触发器与q程/函数的不同点
a. 触发器必d储在数据库中;
b. 触发器自动执?
2. 创徏触发?br />{:1) 语法Q?br /> CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE|AFTER} triggering_event ON table_reference
[FOR EACH ROW [WHEN trigger_condition]]
trigger_body;
2) 范例Q?br /> CREATE OR REPLACE TRIGGER UpdateMajorStats AFTER INSERT OR DELETE OR UPDATE ON students
DECLARE
CURSOR c_Statistics IS
SELECT * FROM students GROUP BY major;
BEGIN
...
END Up;
3. 触发?br />{:1) 三个语句(INSERT/UPDATE/DELETE);
2) 二种cd(之前/之后);
3) 二种U别(row-level/statement-level);
所以一共有 3 X 2 X 2 = 12
4. 触发器的限制
{:1) 不应该用事务控制语?
2) 不能声明MLONG或LONG RAW变量;
3) 可以讉K的表有限?/p>
5. 触发器的M可以讉K的表
{:1) 不可以读取或修改M变化?被DML语句正在修改的表);
2) 不可以读取或修改限制?带有U束的表)的主键、唯一倹{外键列?/p>