您的位置:首页 > 数据库

PLSQL新手新手向入门修炼(1)

2017-07-24 21:02 183 查看

PLSQL新手新手向入门修炼(1)

由于本人对plSQL理解有限,如果文章中出现什么问题,麻烦大家帮我指出来,攻城狮之路,互勉以修远。

本篇文章主要就以下几点来进行展开

(1)plSQL基础写法

(2)plSQL中的控制语句

(3)plSQL中的游标

(4)plSQL意外处理

(5)plSQL存储过程及函数

1.plSQL基础写法

基本格式-匿名块

DECLARE

自定义变量名 类型

BEGIN

SELECT 库中目标变量

INTO 自定义变量

FROM 目标表

WHERE 条件

[EXCEPTION]

异常处理

END;

在编写匿名块的时候有以下几点需要注意的:

1)‘库中目标变量名’与‘自定义变量名’不要相同

2)在声明自定义变量的时候,最好赋予一个初始值,进行初始化,同时在给自定义变量取名的时候要注意场景要求

3)在给自定义变量定义类型的时候

可以使用 %TYPE 来声明与 XX 相同的类型+赋值,如下所示

v_number employees.id%TYPE := &employee_id;

可以使用 %ROWTYPE 来声明某个变量,使得其类型与与某张表的记录或者自定义记录类型保持一致 , 如下所示

根据表的记录

c_record employees%ROWTYPE;

4)在plSQL中 := 是赋值符号, 如果在赋值的同时想要手动输入变量 , 可以使用 &(变量名称) 这样在程序运行的同时就可以先手动输入变量了

5)在plSQL中有些SQL的函数是不能够使用的,如decode函数,分组函数(avg,sum…)

6)plSQL 中insert , update , delete ,merge 等语句与在 SQL 中操作基本相同,但指定条件的时候,可以通知declare进行定义赋值

2.plSQL中的控制语句

plSQL 中存在除了case 语句的另外一种条件语句 , 即 if .. else …

if conditiion then

statements

else

statements

1.在使用控制语句的时候我们对于null的判断需要加以注意

AND 判断

ANDTRUEFALSENULL
TRUETRUEFALSENULL
FALSEFALSEFALSEFALSE
NULLNULLFALSENULL
OR 判断

ORTRUEFALSENULL
TRUETRUETRUETRUE
FALSETRUEFALSENULL
NULLTRUENULLNULL
NOT 判断

TRUEFALSENULL
NOTFALSETRUENULL
一般而言只要记住:

当 AND 的时候 true + null –> null

当 OR 的时候 FALSE+ null –> null

其他情况则按正常情况去判断.

2.循环控制语句

主要分为以下三种:

1)基本循环

LOOP

statement;



EXIT WHEN condition;

END LOOP;

2)Wihle循环

WHILE i < upper_bound LOOP

statement;



END LOOP;

3)For循环

FOR i IN lower_bound..upper_bound LOOP

statement;



END LOOP;

注意:

结合内存表使用,可以实现类似于数组的遍历

首先内存表的定义为:

TYPE table_name IS TABLE OF

目标类型(可以是自定义,某列%type,某表%ROWTYPE)

INDEX BY BINARY_INTEGER;

通过 index by binary_integer 来当做数组的脚标,以便于遍历

我们来举个栗子:

DECLARE
TYPE STUDENT_TYPE IS TABLE OF STUDENT%ROWTYPE
INDEX BY BINARY_INTEGER;
C_STUDENT STUDENT_TYPE;
V_COUNT   NUMBER(7, 2) := 17;
BEGIN
FOR i IN 1 .. V_COUNT LOOP
SELECT *
INTO C_STUDENT(i)
FROM STUDENT
WHERE TO_NUMBER(SUBSTR(STUDENT.STUDENT_NO, 2, 3)) = i;
END LOOP;
FOR i IN C_STUDENT.FIRST .. C_STUDENT.LAST LOOP
DBMS_OUTPUT.PUT_LINE(C_STUDENT(i).STUDENT_NAME);
END LOOP;
END;


这个例子中还存在一个问题,就是说第一个循环的最终变量是手动输入的,我们需要通过表达式来使这个变量呈现动态变化,这个问题的解决方案我会贴在我日后的文章中

3.plSQL中的游标

游标是plSQL中很重要的一部分,所以务必通过实际验证以校验自己的了解情况如何,游标分为两种类型

显式

由程序员声明的游标,对于返回多行结果的SQL语句返回结果,可以使用显式游标独立的处理其中每一行的数据

隐式

oracle 通过使用隐式游标来解析和执行我们提交的SQL语句

1)关于隐式存在以下几条有用的属性:(重要)

*  SQL%ROWCOUNT  受最近的SQL语句影响的行数
*  SQL%FOUND     最近的SQL语句是否影响了一行以上的数据
*  SQL%NOTFOUND  最近的SQL语句是否未影响任何数据
*  SQL%ISOPEN    对于隐式游标而言永远为false


2)关于显式游标的使用(重要)

有以下几个步骤:

声明游标

打开游标

提取当前行到变量

测试行的存在

关闭游标

我们来举个栗子:

DECLARE
V_ST_NO STUDENT.STUDENT_NO%TYPE;
V_ST_NAME STUDENT.STUDENT_NAME%TYPE;
CURSOR ST_CURSOR IS
SELECT STUDENT_NO,STUDENT_NAME
FROM STUDENT;
BEGIN
OPEN  ST_CURSOR;
LOOP
FETCH ST_CURSOR INTO V_ST_NO , V_ST_NAME;
EXIT WHEN ST_CURSOR%ROWCOUNT > 10 OR ST_CURSOR%NOTFOUND;
DBMS_OUTPUT.put_line(V_ST_NO  ||' ' || V_ST_NAME );
END LOOP;
CLOSE ST_CURSOR;
END;


在这段代码中我们将student表中的id,name通过游标将前十条进行了输出,在这之中主要要注意的这段:

FETCH ST_CURSOR INTO V_ST_NO , V_ST_NAME;

–将游标中的值插入到指定自定义变量中

EXIT WHEN ST_CURSOR%ROWCOUNT > 10 OR ST_CURSOR%NOTFOUND;

–通过对最近执行语句条数的判断,从而决定何时跳出循环

我们还可以通过 FOR 循环语句来使用游标,相对之前的这种使用方式写法较为简单,但可读性没有之前这条来的强,但是使用 FOR 循环语句来使用游标在效率上比前一种块上许多

我们来举个栗子:

DECLARE
V_ST_NO STUDENT.STUDENT_NO%TYPE;
V_ST_NAME STUDENT.STUDENT_NAME%TYPE;
BEGIN
FOR ST_CURSOR IN(SELECT STUDENT_NO,STUDENT_NAME
FROM STUDENT) LOOP
V_ST_NO := ST_CURSOR.STUDENT_NO;
V_ST_NAME := ST_CURSOR.STUDENT_NAME;
DBMS_OUTPUT.put_line(V_ST_NO  ||' ' || V_ST_NAME );
END LOOP ;
END;


在使用游标的时候我们还可以使用带参数的游标,来缩小范围以提高效率。

在某些情况下我们使用游标是为了更新或者删除一些记录,在这种情况下我们需要对这部分数据进行锁定,此时我们需要在声明的最后面加上一条语句: for update of 目标条件 nowait

还有一种情况就是由于我们经常要逐条处理游标中的每一条记录,在循环体中做update 或者 delete 是需要有where 指向游标的当前记录,我们可以有更简单的 where 条件写法,我们可以将where条件语句写在游标中,如下:

DECLARE
CURSOR ST_CURSOR IS
SELECT S.STUDENT_NO, S.STUDENT_NAME
FROM   STUDENT S
WHERE  TO_NUMBER(SUBSTR(S.STUDENT_NO, 2, 3))< 11
FOR UPDATE OF STUDENT_NO NOWAIT;
BEGIN
FOR ST_record IN ST_CURSOR
LOOP
IF TO_NUMBER(SUBSTR(ST_record.STUDENT_NO, 2, 3)) < 11 THEN
UPDATE STUDENT
SET  STUDENT_NO = ST_record.STUDENT_NO || 'M'
WHERE CURRENT OF ST_CURSOR;
END IF;
END LOOP;
END;


4.plSQL意外处理

1)处理预定义例外

在 oracle 中存在一些常见例外,它已经帮我们预定义好了,使用时无需实现声明如:

——NO_DATA_FOUND

——TOO_MANY_ROWS

——INVALID_CURSOR

——ZERO_DIVIDE等

栗子如下:

BEGIN
...
EXCEPTION
WHEN NO_DATA_FOUND THEN
statement;
WHEN TOO_MANY_ROWS THEN
statement;
WHEN OTHERS THEN
STATEMENT;
END;


我们可以通过使用 SQLCODE , SQLERRM 来分别返回Oracle 的错误号和错误描述,栗子如下:

DECLARE
V_ERROR_CODE    NUMBER;
V_ERROR_MESSAGE VARCHAR2(255);
BEGIN
.. .
EXCEPTION
...
WHEN OTHERS THEN ROLLBACK;
V_ERROR_CODE    := SQLCODE;
V_ERROR_MESSAGE := SQLERRM;
INSERT INTO ERRORS
VALUES (V_ERROR_CODE, V_ERROR_MESSAGE);
END;


一般而言很多情况下例外都是数据库之前没有预声明的,此时就需要我们对这些例外进行声明处理,一般而言我们通过raise语句显示的抛出例外

如果觉得先声明再抛出例外很麻烦,也可以使用 RAISE_APPLICATION_ERROR()函数进行简化处理

如下所示

RAISE_APPLICATION_ERROR(-22202 , ‘This is not a valid manager ‘);

同时,还请注意,当我们在使用匿名块的嵌套的时候,当内层例外没有被处理,会一层一层向外传递,直到外层处理位置,或直接报错

5.plSQL存储过程及函数

这个存储过程及函数的调用是很重要的一块,通过这一块的调用,可以大幅提高代码的复用性,下文会通过我的一些代码以及个人看法来进行介绍:

1)存储过程的定义,我们举个栗子来看看怎么写:

CREATE OR REPLACE PROCEDURE ST_PROCEDURE
(ST_NO   IN STUDENT.STUDENT_NO%TYPE,
ST_NAME OUT STUDENT.STUDENT_NAME%TYPE,
ST_GEN  IN OUT STUDENT.STUDENT_GENDER%TYPE) IS
BEGIN
SELECT S.STUDENT_NAME, S.STUDENT_GENDER
INTO ST_NAME, ST_GEN
FROM STUDENT S
WHERE S.STUDENT_NO = ST_NO;
END ST_PROCEDURE;


一般而言大致模板如此,我们需要注意的主要有3点:

对于()中的参数有三种关系可以进行书写,IN ,OUT , IN OUT 。

*IN 指的是由运行环境输入至存储过程中

*OUT 指的是由存储过程返回至运行环境

*IN OUT 则是既可以输入,也可以输出

存储过程不存在返回值,即RETURN ,但可以输出值

对于在存储过程中出现的例外,如果在存储过程中没有解决,则会直接跳出存储过程,至调用存储过程的外部例外处理程序中

2)函数的定义,我们举个栗子来看看怎么写:

CREATE OR REPLACE FUNCTION ST_FUNCTION
(ST_NO   IN STUDENT.STUDENT_NO%TYPE)
RETURN VARCHAR2 IS
V_NAME VARCHAR2(200);
BEGIN
SELECT S.STUDENT_NAME
INTO ST_NAME
FROM STUDENT S
WHERE S.STUDENT_NO = ST_NO;
V_NAME := ST_NAME;
RETURN(V_NAME);
END ST_FUNCTION;


函数的使用范围很广,因为其拥有返回值,其返回值可以是单独的值,也可以是一个表对象,所以在使用的时候存在以下几点需要注意的:

(1)函数只能被调用,与存储关系不同的,存储关系可以单独进行运行,但是函数只能在语句中被调用;

(2)函数中只能存在 IN 模式的参数;

(3)只能接收或者返回SQL类型的数据,不能接收plSQL特有的参数比如recored ,plSQL内存表等;

(4)在SQL语句中使用函数,函数中不能包含DML语句,事务结束语句等;

(5)在UPDATE / DETELE 语句中调用函数,函数中不能存在针对该表的select 语句。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  plsql 数据库