Oracle数据库存储过程

1.存储过程简述

存储过程:它是大型数据库中常用的、一组为了完成特定功能的SQL语句集。

存储过程在Oracl中是procedure

2.存储过程优点

2.1.性能高(效率高)

存储过程相较于普通的SQL语句来说,它的性能非常的好,这是因为存储过程在第一次编译之后,是存储在数据库的,用的时候直接使用存储过程名就可以(第一次之后不需要再编译),普通的SQL语句每次执行都需要先编译再执行。

2.2.低流量

存储过程在编译好之后直接存放在数据库,因此不需要再传输大量字符串类型的SQL语句。

2.3.高复用

存储过程在写好之后,需要使用这个特定功能的都可以调用。

2.4.易维护

存储过程在编写好之后,如果需要修改需求,也很容易。

2.5.高安全

完成某个特定功能的存储过程一般只有特定身份的人才能使用,所以具有身份限制

3.存储过程结构

3.1.存储过程的基本结构

基本结构包含三大部分:声明过程,执行部分,存储过程异常(多用于增强代码的容错性和健壮性)。

3.2.无参存储过程

CREATE OR REPLACE PROCEDURE 存储过程名 IS/AS     //IS和AS选择哪个均可,无区别

        变量1 DATE;

        变量2 NUMBER;

BEGIN

        //需要执行的SQL语句

        EXCEPTION;    //存储过程异常

END

3.3.有参存储过程

CREATE OR REPLACE PROCEDURE 存储过程名(param student.id%TYPE) AS/IS

name student.name%TYPE;

age number :=20;

BEGIN

        //需要执行的SQL语句

        EXCEPTION;    //存储过程异常

END

3.4.进行赋值的有参存储过程

CREATE OR REPLACE PROCEDURE 存储过程名(sno in  varchar,    //in代表的传入参数

        sname out varchar,         //out代表的是返回值

        sage number) AS            //没有指定是in或out的时候,默认是in

        total NUMBER := 0;  

BEGIN

        SELECT COUNT(1) INTO total FROM student s WHERE s.age = sage;

        dbms_output.put_line("符合该区间的学生有:"|| total || "人");

        EXCEPTION

            WHEN two_money_throws THEN

            DBMS_OUTPUT.PUT_LINE("返回值大于1行!");

END

3.5.存储过程语法

运算符:

SELECT ... INTO ...赋值

SELECT INTO语句可以将select到的结果赋值给一个或多个变量。

CREATE OR REPLACE PROCEDURE 存储过程名 IS

sname VARCHAR2;    //学生姓名

sage NUMBER;    //学生年龄

saddress VARCHAR2;    //学生籍贯

BEGIN 

    select s_address into saddress from student where s_grade = 100;

    select s_name,s_age into sname,sage from student where s_grade = 100;

END

IF...END IF/IF...ELSE...END IF    选择语句

IF...END IF

IF sex=1 THEN

    dbms_output.put_line("男");

END IF

IF...ELSE IF...END IF

IF sex=1 THEN

    dbms_output.put_line("男");

ELSE

    dbms_output.put_line("女");

END IF

基本循环/while循环/for循环

基本循环

LOOP 

    IF 表达式 THEN

          需要执行的操作

    END IF

END LOOP

while循环

WHILE 表达式 LOOP

    需要执行的操作

END LOOP

for循环

FOR x IN 20..30 LOOP

    需要执行的操作

END LOOP

游标

游标是SQL的一个工作区,由系统或者用户以变量的形式来定义的。

游标的类型:显式游标 / 隐式游标

游标的作用:它用来临时存储从数据库读取出来的数据块

游标的好处:游标可以把读取出来的数据临时存放在计算机内存中,使用的时候不需要频繁的和磁盘进行数据交换,提高了效率和速度

游标的特点:正常的DML操作(增删改)和只从数据库中读取一行数据的查操作系统会使用一个隐式游标,但是对于读取多行数据,就需要定义一个显式游标,并通过与游标有关的语句进行处理(所以,显式游标通常对应一条返回多行多列的查询语句)。    一旦打开游标,语句结果就会传到游标变量中,最后应用程序在从游标变量中分解出需要的数据进行处理

隐式游标:隐式游标对应的是DML操作和读取单行数据的查询操作,可以通过名字SQL的方式去访问,但是隐式游标只能访问上一个执行的DML和单行读取的查询操作,所以在刚执行完操作之后,需要马上使用SQL游标名进行访问属性。

隐式游标的四个属性

        隐式游标属性                        返回值            意义

1.    SQL%ROWCOUNT                整型               表示DML执行成功影响的数据行数

2.    SQL%FOUND                        布尔值            值为TRUE表示DML或查询操作成功

3.    SQL%NOTFOUND                 布尔值            和SQL%FOUND相反

4.    SQL%ISOPEN                        布尔值            DML执行时为TRUE,执行结束为FALSE

例子:

SET SERVEROUTPUT ON                    //设置环境变量,否则无法正常输出返回信息

    BEGIN

           UPDATE emp SET sal=sal+100 WHERE empno=1234;  

            IF SQL%FOUND THEN

                DBMS_OUTPUT.PUT_LINE("修改成功!");

                COMMIT;

            ELSE

                DBMS_OUTPUT.PUT_LINE("修改失败!");

            END IF;

    END;

显式游标:

    声明:CURSOR 游标名[(参1 类型 [参2 类型...])]

                IS SELECT语句;

        注意:参数为可选的,但是在使用游标的时候,必须传入实际参数;SELECT语句除了INTO子句不可写之外,其他的都可以;在SELECT语句中,可以使用在游标之前定义的变量。

    打开游标:OPEN 游标名[(参1 类型 [参2 类型...])];

        注意:打开游标的时候,SELECT的查询结果就会被传到游标中。

    提取数据:FETCH 游标名 INTO 变量名1 [变量名2];

                     或:FETCH 游标名 INTO 记录变量;

        注意:游标中有一个指针指向游标数据区,但是指针一次只能指向一行数据,返回多行数据需要重复执行,可以搭配使用循环。循环控制可以通过访问游标属性来实现。        第一种方式:变量名是用于从游标中接收数据的变量,需要事先定义。参数的数量和类型需要和select语句中的一致。第二种方式:一次将一行数据记录到变量中,需要通过%ROWTYPE事先定义记录变量。CLOSE

    关闭游标:CLOSE 游标名;

        注意:显式游标必须显示关闭,一旦关闭就会释放游标的资源,想要使用必须再次打开。

例子:

//采用第一种方法:

SET SERVEROUTPUT ON    //设置环境变量

    DECLARE            //定义变量(局部变量,作用类似BEGIN)

        name VARCHAR2(10);

        job    VARCHAR2(10);

        CURSOR emp_cursor IS        //声明显式游标emp_cursor 

        SELECT name,job FROM emp WHERE enpno = 100;    //执行查询语句

        BEGIN

            OPEN emp_cursor;        //打开游标,select语句执行结果返回到游标数据区

            FETCH emp_cursor INTO name,job ;       //读取游标中的数据

            DBMS_OUTPUT.PUT_LINE(name || "," || job);    //输出获取的数据

            CLOSE emp_cursor;    //关闭游标

        END;


//采用第二种方法:

SET SERVEROUTPUT ON        //设置环境变量

    DECLARE    

        CURSOR emp_cursor IS        //定义游标

            SELECT name,job,sal FROM emp WHERE empno = 7788;

            emp_record emp_cursor %ROWTYPE;    //定义变量emp_record的类型

     BEGIN       

        OPEN emp_cursor ;        //打开游标

        FETCH emp_cursor  INTO  emp_record;       //将查询到的数据传给变量emp_record

        DBMS_OUTPUT.PUT_LINE(emp_record.name || "," || emp_record.age || "," ||                        emp_record.sal);

        CLOSE emp_cursor;        //关闭游标


//游标搭配循环

SET SERVEROUTPUT ON  

        DECLARE          

             V_ename VARCHAR2(10);           

             V_sal NUMBER(5);           

             CURSOR emp_cursor IS       

             SELECT ename,sal FROM emp ORDER BY sal DESC;           

            BEGIN           

                OPEN emp_cursor;                

                FOR I IN 1..3 LOOP              

                     FETCH emp_cursor INTO v_ename,v_sal;           

                     DBMS_OUTPUT.PUT_LINE(v_ename||','||v_sal);             

                  END LOOP;                 

                  CLOSE emp_cursor;             

               END;

4.存储过程高级

存储过程的执行过程:存储过程在编译之后,每遇到一条语句都会判断是pl/sql还是sql,然后给对应的引擎去处理。

存储过程存在的问题:当遇到大数据量的处理时,执行焦点就会不断地切换。过多的上下文切换会(pl/sql和sql引擎的来回切换成为上下文切换)造成沉重的负担,导致效率的下降

解决问题的方法:Oracl8i之后PL/SQL引入两个新数据操纵语句——FORALLBUIK COLLECT。这两个语句减少了上下文切换(一次切换多次执行)。

4.1.BUIK COLLECT

BUIK COLLECT的特点是批量检索,然后将检索结果绑定到一个集合变量中,和游标cursor一条条的检索是不同的。BUIK COLLECT可以在SELECT INTO、FETCH INTO、RETURNING INTO中使用。

//SELSECT INTO             查询出来的结果集合赋值给另一个集合变量 

语法:SELECT 查询字段 BUIK COLLECT INTO 存值集合变量 FROM 表名 WHERE 条件;

例:SELECT s_name BUIK COLLECT INTO arr_name FROM student WHERE s_age>10;

//FETCH INTO            将集合中的一部分数据赋值给另一个集合

语法:FETCH 数据集合 BUIK COLLECT INTO 数据集合 [ LIMIT 每次获取的行数 ];

例:

//声明一个游标 ,并存放年龄大于10的学生编号

CURSOR cur_no IS SELECT s_no FROM student WHERE s_age>10; 

//声明一个数组,类型和游标的每个元素一样

TYPE arr_no IS VARRY(10) OF cur_no%ROWTYPE;

//声明一个类型为arr_no类型的变量

no arr_no;

BEGIN

    FETCH cur_no BUIK COLLECT INTO no LIMIT 100;    //每次获取100条数据给该变量

    FORALL i IN 1..no.count SAVE EXCEPTIONS 

            UPDATE student SET s_grade=s_grade-1 WHERE no(i); 

END

//RETURNING        将进行DML操作影响到的数据行的列值保存进指定的PL/SQL变量中

语法:DML语句 RETURNING 表字段1[,表字段2... ] BUIK COLLECT INTO 字段同类型集合;

例:

TYPE name_collect IS TABLE student.s_name%TYPE;

names name_collect;

BEGIN 

    UPDATE student SET s_grade=s_grade-1 WHERE s_age<10

    RETURNING  s_name BUIK COLLECT INTO names;

END

注意:

1.不能对键为字符串类型的关联数组使用BUIK COLLECT子句

2.只能在服务器端的程序中使用BUIK COLLECT子句,在客户端使用会报错(不支持)

3.BUIK COLLECT INTO子句的目标对象必须是集合类型

4.RETURNING中不能使用复合目标(对象类型)

5.如果有一个或多个隐式数据类型转换,复合对象不能在BUIK COLLECT INTO中作为目标对象使用

4.2.FORALL

FORALL主要的作用就是增强DML的操作性,简化代码

语法:FORALL 下标 IN 范围 [ SAVE EXCEPIONS ] DML语句;

例:FORALL i IN 5..10 DELETE FROM student WHERE s_grade=i; 

在执行DML语句的时候,会可能遇到异常,可能会导致事件的回滚。如果在FORALL的后面没有加上SAVE EXCEPTIONS语句,DML语句会在执行到一半的时候停下来。如果加上了SAVE EXCEPTIONS语句,那么DML语句会继续向下执行,异常信息则会记录在SQL%BULK_EXCEPTIONS游标属性中,这个游标属性是一个信息记录集合,每条记录里面有两个字段,分别是发生异常的FORALL语句的迭代编号和错误代码,例:(1,03400)。SQL%BULK_EXCEPTIONS这个集合保存着最近一次可能发生异常的信息,而异常个数则由它的COUNT属性表示,即:SQL%BULK_EXCEPTIONS.COUNT

4.3.INDICES OF

INDICES OF是用于处理稀疏数组或包含间隙的数组的。因为Oracl数据库在10g之前有一个限制:在IN范围中,会从第一行到最后一行依次读取数据库的内容,如果遇到了一个未定义的行或者是被删除的行, 那么就会引发ORA-22160的异常(ORA-22160: element at index [N] does not exist).

语法:FORALL i INDICES OF 集合 [ SAVE EXCEPTIONS ] sql语句;

例:FORALL i INDICES OF arr_stu

            INSERT INTO student VALUES(arr_stu(i).name,arr_stu(i).age,arr_stu(i).grade) ;

4.4.VALUES OF 

VALUES OF可以指定FORALL语句中循环计数器的值来自于指定集合中元素的值。VALUES OF适用于绑定数组为稀疏数组的情况(也可以不是稀疏数组)。但是如果VALUES OF使用的集合是联合数组,则必须使用PLS_INTEGER和BINARY_INTEGER进项索引,即VALUES OF所使用的元素必须是PLS_INTEGER和BINARY_INTEGER。

注意:当VALUES OF子句引用的集合为空的时候,FORALL语句会报错。

语法:FORALL i IN VALUES OF 集合 [ SAVE EXCEPTIONS ] sql语句;

5.联合数组和嵌套表

5.1.联合数组

联合数组类似于一张简单的SQL表,可以按照主键检索数据,且数据元素个数无限制。

存储的数据是没有顺序的,当使用变量来检索数据的时候,每个数据会分配一个从1开始的下标。   

下标可以为负,且下标的数据类型支持BINARY_INTEGER,PLS_INTEGER,VARCHAR2。

不能作为表列的数据类型使用,只能作为PL/SQL复合数据类型使用

存放的数据是临时数据,所以不支持insert,select into等SQL语句,等同于sql server中的表变量

语法:

//element_type为联合数组元数据指定数据类型(先使用TYPE声明表结构

TYPE type_name IS TABLE OF element_type [ NOT NULL ]

INDEX BY key_type;        //元素下标的使用类型

table_name TYPE_NAME;        //使用声明的TYPE类型来声明实际数组名

5.2.嵌套表

元素下标从1开始,长度可以动态增长,没有限制。

嵌套表的数组元素可以是稀疏数组,它的语法和联合语法相似,但是没有index by子句

嵌套表必须先初始化才能引用其中元素,若初始化值为空,则后面需要使用extend来扩展其大小

嵌套表初始化的时候是密集的,但是允许有空隙,所以支持使用内置过程delete来从嵌套表删除元素

嵌套表类型可以作为表列的数据类型来使用。

语法:TYPE type_name IS TABLE OF element_type [ NOT NULL ]

            table_name TYPE_NAME;

参考文章:https://blog.csdn.net/weixin_41968788/article/details/83659164

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350