说明:SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML, 数据定义语言DDL,数据控制语言DCL。
0.调试
点击procedure名,右键选择调试。即可进入调试模式。找到procedure,点击右键,查看,可看到编译错误信息。
Dbms_output.Put_line('打印内容:' || v_total); --打印
v_str:=&dno; 其中 &表示键盘输入。即接收键盘输入的值dno表示Name。
1.基本用法
查看所有的存储过程:
select object_name,object_type,status from user_objects where OBJECT_TYPE='PROCEDURE';
查看某个存储过程:
SELECT text FROM user_source WHERE NAME = 'procedure_name';
删除:
drop procedure procedure_name;
新增:
create or replace procedure procedure_name;
CREATE OR REPLACE PROCEDURE test1 IS
v_total NUMBER;
BEGIN
SELECT COUNT(*) INTO v_total FROM user;
Dbms_output.Put_line(v_total); --打印
END;
1 存储过程创建语法: 2 3create or replace procedure procedure_name(param1 in type,param2 out type,param3 in out type) --参数类型不需要定义值范围 4 5 as 6 7 变量1 类型(值范围); 8 9 变量2 类型(值范围); 10 11 Begin 12 ........... 13 END [procedure_name];
1 begin 2 execute immediate 'ALTER TABLE RECORD_XWZX5_left ADD (ID NUMBER)'; 3 execute immediate 'ALTER TABLE RECORD_XWZX5_right ADD (ID NUMBER)'; 4 update RECORD_XWZX5_right set ID = ROWNUM; 5 update RECORD_XWZX5_left set ID = ROWNUM; 6 commit; 7 end ; 8 9 执行多条插入语句
1. 其中的 IS 可以用 AS来替代,两个是同义词。(oracle数据库表名不能用as)
在视图(VIEW)中只能用AS不能用IS
在游标(CURSOR)中只能用IS不能用AS
2. Select 必须有 INTO 接收值的变量(select ** into v_name ),不然报错,在赋值时最好用count(*)测试下,是否有多值和无值的情况发生,在Exception中处理结果。
调用:
// pLsql调用
BEGIN test1(); END;
// 外部程序调用[
EXECUTE
]|[CALL] procedure_name[(parameter,…n)]
2. 变量
DECLARE v1 hr_user.oa_name%TYPE;
赋值:
v1:='zhangsan';
v_count INT :=30;
声明时不能够赋值,只能default形式设定默认值。
3.参数
存储过程的参数不用带取值范围直接定义类型即可,且形式只有IN和OUT两种,或者将两个都共存。
CREATE OR REPLACE PROCEDURE test1(v1 in varchar, v2 out varchar,v3 in out varchar) 默认为IN形式。
1 /* 创建 */ 2 CREATE OR REPLACE PROCEDURE test1(v1 VARCHAR, v2 OUT INT) IS 3 BEGIN 4 SELECT COUNT(*) INTO v2 FROM user WHERE name = v1; 5 Dbms_output.Put_line(v2); 6 EXCEPTION 7 WHEN NO_DATA_FOUND THEN 8 v2 := 0; 9 Dbms_output.Put_line(v2); 10 WHEN OTHERS THEN 11 ROLLBACK; 12 END; 13 14 15 /* 调用 */ 16 DECLARE v1 VARCHAR(100); 17 v2 INT; 18 BEGIN 19 v1:='zhangsan'; 20 test1(v1, v2); 21 END;
另一种声明变量参数的方式%type。
%type 表示将参数的类型和表中的某个字段绑定,使用字段定义的参数类型。这样当参数类型变化时,存储过程中的跟着变化。
CREATE OR REPLACE PROCEDURE test1(v1 user.name%TYPE, v2 OUT INT) IS
PROCEDURE APPS.TEST1 编译错误 错误:PLS-00363: 表达式 'V_INCREMENT' 不能用作赋值目标 In out 被作为了常量,因此不能够被赋值,只能获取。
默认传参:
默认存储过程传参是按照前后顺序进行,
test1(va,vb);
如果不按照前后顺序,则使用以下方式:
1 DECLARE 2 va hr_user.oa_name%TYPE; 3 ve INT; 4 BEGIN 5 va:='zhangsan'; 6 test1(v1 =>va, v2 =>ve); 7 END;
4.raise ***主动抛出异常
1 CREATE OR REPLACE PROCEDURE test1(v1 VARCHAR, v2 OUT INT) IS 2 BEGIN 3 SELECT COUNT(*) INTO v2 FROM user WHERE name = v1; 4 Dbms_output.Put_line(v2); 5 IF v2 > 1 THEN 6 RAISE TOO_MANY_ROWS; 7 ELSIF v2 = 0 THEN 8 RAISE NO_DATA_FOUND; 9 END IF; 10 EXCEPTION 11 WHEN NO_DATA_FOUND THEN 12 v2 := 0; 13 Dbms_output.Put_line('未查询到任何数据'); 14 WHEN TOO_MANY_ROWS THEN 15 Dbms_output.Put_line('返回多行数据'); 16 WHEN OTHERS THEN 17 ROLLBACK; 18 END;
命名的系统异常 产生原因
ACCESS_INTO_NULL 未定义对象
CASE_NOT_FOUND CASE 中若未包含相应的 WHEN ,并且没有设置
ELSE 时
COLLECTION_IS_NULL 集合元素未初始化
CURSER_ALREADY_OPEN 游标已经打开
DUP_VAL_ON_INDEX 唯一索引对应的列上有重复的值
INVALID_CURSOR 在不合法的游标上进行操作
INVALID_NUMBER 内嵌的 SQL 语句不能将字符转换为数字
NO_DATA_FOUND 使用 select into 未返回行,或应用索引表未初始化的
TOO_MANY_ROWS 执行 select into 时,结果集超过一行
ZERO_DIVIDE 除数为 0
SUBSCRIPT_BEYOND_COUNT 元素下标超过嵌套表或 VARRAY 的最大值
SUBSCRIPT_OUTSIDE_LIMIT 使用嵌套表或 VARRAY 时,将下标指定为负数
VALUE_ERROR 赋值时,变量长度不足以容纳实际数据
LOGIN_DENIED PL/SQL 应用程序连接到 oracle 数据库时,提供了不
正确的用户名或密码
NOT_LOGGED_ON PL/SQL 应用程序在没有连接 oralce 数据库的情况下
访问数据
PROGRAM_ERROR PL/SQL 内部问题,可能需要重装数据字典& pl./SQL
系统包
ROWTYPE_MISMATCH 宿主游标变量与 PL/SQL 游标变量的返回类型不兼容
SELF_IS_NULL 使用对象类型时,在 null 对象上调用对象方法
STORAGE_ERROR 运行 PL/SQL 时,超出内存空间
SYS_INVALID_ID 无效的 ROWID 字符串
TIMEOUT_ON_RESOURCE Oracle 在等待资源时超时
6. 流程结构控制
IF: if 条件 then
else
end if
----------------------
if 条件 then
elsif 条件 then
end if
这里中间是“ELSIF”,而不是ELSE IF 。这里需要特别注意
WHILE:
WHILE ... LOOP
[BEGIN]
[END];
END LOOP;
1 CREATE OR REPLACE PROCEDURE TEST1(v_increment IN INT) IS 2 v_count INT := 30; 3 v_icre INT DEFAULT v_increment; 4 BEGIN 5 WHILE v_icre < v_count LOOP 6 BEGIN --可加可不加 7 Dbms_output.Put_line('打印内容:' || v_icre); 8 v_icre := v_icre + 1; 9 END; 10 END LOOP; 11 END TEST1;
7. 游标cursor使用
cursor 只能用IS修饰。
注意:因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;游标类型:隐式游标和显式游标。
隐式游标:DML(数据操作语言包括:INSERT,DELETE,UPDATE,SELECT... INTO 等单行语句) SQL语句都会使用隐式游标调用。
属性 | 返回值类型 | 说明 |
SQL%ROWCOUNT | 整型 | 代表DML语句成功执行的数据行数 |
SQL%FOUND | 布尔型 | TRUE代表插入、删除、更新或单行查询操作成功 |
SQL%NOTFOUND | 布尔型 | 与SQL%FOUND属性返回值相反 |
SQL%ISOPEN | 布尔型 | DML执行过程中为真,结束后为假 |
显式游标:DQL(查询语句select) sql返回多行数据时,使用显式游标调用。
%Found :Fetch语句(获取记录)执行情况True or False。 %NotFound : 最后一条记录是否提取出True or False。 %ISOpen : 游标是否打开True or False。 %RowCount :游标当前提取的行数 。
定义: CURSOR cur IS SELECT * FROM user;
传参: v_cur cur%rowType;一行数据类型
FOR循环游标隐式打开游标,自动滚动获取一条记录,并自动创建临时记录类型变量存储记录。处理完后自动关闭游标。
fetch ... into ... 游标开始在空行,使用fetch into 使得游标进入下一行
注意: 只是要注意用更新游标的时候,不能在游标期间commit. 否则会报
ORA-01002: fetch out of sequence
就是COMMIT;导致错误
在打开有for update的cursor时,系统会给取出的数据加上排他锁(exclusive),
这样在这个锁释放前其他用户不能对这些记录作update、delete和加锁。
而我一旦执行了commit,锁就释放了,游标也变成无效的,再去fetch数据时就出现错误了。
因而要把commit放在循环外,等到所有数据处理完成后再commit,然后关闭cursor
使用(for ... in ... loop .... end loop直接开始游标):
for cur_result in cur loop
v_name:=cur_result.column_name;
end loop;
1 CREATE OR REPLACE PROCEDURE TEST1(v_increment IN INT) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur IS 5 SELECT * FROM user WHERE rownum < 50; 6 BEGIN 7 FOR cur_result IN cur LOOP 8 v_name := cur_result.name; 9 v_type := cur_result.type; 10 Dbms_output.Put_line('打印内容:' || v_name || ' ' || v_type); 11 END LOOP; 12 END TEST1;
使用2(loop fetch cur into ...):
1 CREATE OR REPLACE PROCEDURE TEST1(v_increment IN INT) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur IS 5 SELECT name, type FROM user WHERE rownum < 50; 6 BEGIN 7 OPEN cur; 8 LOOP 9 FETCH cur 10 INTO v_name, v_type; 11 EXIT WHEN cur%NOTFOUND; 12 BEGIN 13 Dbms_output.Put_line('打印内容:' || v_name || ' ' || v_type); 14 END; 15 END LOOP; 16 CLOSE cur; 17 END TEST1;
使用3(while):
1 CREATE OR REPLACE PROCEDURE TEST1(v_increment IN INT) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur IS 5 SELECT name, type FROM user WHERE rownum < 50; 6 v_row cur%ROWTYPE; --变量定义必须在begin之前 7 BEGIN 8 OPEN cur; 9 FETCH cur INTO v_row; --fetch将值赋予v_row 10 WHILE cur%FOUND LOOP 11 Dbms_output.Put_line('打印内容:' || v_row.name || ' ' || 12 v_row.type); 13 FETCH cur INTO v_row; 14 END LOOP; 15 CLOSE cur; 16 END TEST1;
4.游标带参
1 CREATE OR REPLACE PROCEDURE TEST1(v_oname IN VARCHAR) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur(v_name1 VARCHAR) IS 5 SELECT name, type FROM user 6 WHERE name = v_name1 7 AND rownum < 50; 8 v_row cur%ROWTYPE; 9 BEGIN 10 OPEN cur(v_oname); 11 FETCH cur 12 INTO v_row; 13 WHILE cur%FOUND LOOP 14 Dbms_output.Put_line('打印内容:' || v_row.name || ' ' || 15 v_row.type); 16 FETCH cur 17 INTO v_row; 18 END LOOP; 19 CLOSE cur; 20 END TEST1;
5. 游标更新和删除
CURSOR cursor_name IS select_statement FOR UPDATE [OF column_reference] [NOWAITE]; -- OF子句指定对特定表加锁。 UPDATE table_name SET column=.. WHERE CURRENT OF cursor_name; DELETE table_name WHERE CURRENT OF cursor_name;
6.批量提取
FETCH ... BULK COLLECT INTO ...[LIMIT row_number];
1 CREATE OR REPLACE PROCEDURE TEST1(v_oname IN VARCHAR) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur IS 5 SELECT * 6 FROM user 7 WHERE name LIKE '%' || v_oname || '%' 8 AND rownum < 50; 9 v_row cur%ROWTYPE; 10 11 TYPE type_user IS TABLE OF user%ROWTYPE INDEX BY BINARY_INTEGER; 12 user_table type_user; 13 BEGIN 14 OPEN cur; 15 FETCH cur BULK COLLECT 16 INTO user_table limit 5; 17 CLOSE cur; 18 FOR i IN 1 .. user_table.count LOOP 19 Dbms_output.Put_line('打印内容:' || user_table(i).name || ' ' || user_table(i) .type); 20 END LOOP; 21 END TEST1;
参考:
Oracle存储过程创建及调用(http://www.cnblogs.com/chinafine/articles/1776094.html)
Oracle存储过程学习(http://www.cnblogs.com/chuncn/archive/2009/01/29/1381291.html)
Oracle游标使用全解(http://blog.csdn.net/jeathenzhang/article/details/8853607)
plsql游标详解(http://blog.csdn.net/kb5706/article/details/7575445)