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

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 判断

AND TRUE FALSE NULL
TRUE TRUE FALSE NULL
FALSE FALSE FALSE FALSE
NULL NULL FALSE NULL



OR 判断

OR TRUE FALSE NULL
TRUE TRUE TRUE TRUE
FALSE TRUE FALSE NULL
NULL TRUE NULL NULL



NOT 判断

TRUE FALSE NULL
NOT FALSE TRUE NULL



一般而言只要记住:

  • 当 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)