Oracle存储过程学习

点点圈 提交于 2020-02-07 15:34:50

说明: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)

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!