MySQL, Oracle, Linux, 软件架构及大数据技术知识分享平台

网站首页 > 数据库 / 正文

PLSQL一些常用的知识点

2024-11-26 20:47 huorong 数据库 6 ℃ 0 评论

1、背景

此处简单的记录一下在 oracle中如何使用plsql语法,记录一些简单的例子,防止以后忘记。

2、变量的声明

  1. declare
  2. -- 声明变量
  3. v_name varchar2(20);
  4. -- 此变量由 select into 赋值
  5. v_man_sex number;
  6. -- v_sex 变量的类型和 student表中的 sex 字段的类型一致
  7. v_sex student.sex%TYPE;
  8. -- v_row 中保存的是 student表中的一整行字段, 也可以是游标中的一整行
  9. v_row student%rowtype;
  10. -- 声明变量并赋值
  11. v_addr varchar2(100) := '湖北省';
  12. -- 声明日期变量
  13. v_date date := sysdate;

  14. -- 定义一个记录类型
  15. type STUDENT_INFO is record
  16. (
  17. student_id student.student_id%TYPE,
  18. student_name student.student_name%TYPE
  19. );
  20. -- 定义基于记录的嵌套表
  21. type nested_student_info is table of STUDENT_INFO;
  22. -- 声明变量
  23. student_list nested_student_info;

  24. begin
  25. -- 直接赋值
  26. v_name := '直接赋值';
  27. v_date := to_date('2023-12-12', 'yyyy-mm-dd');
  28. -- 单个字段语句赋值
  29. select count(*) into v_man_sex from student where sex = 1;
  30. -- 多个字段赋值
  31. select student_name,sex into v_name,v_sex from student where student_id = 'S003';
  32. -- 获取一行数据 ( 此处需要查询出所有的字段,否则可能报错 )
  33. select student_id,student_name,sex,CREATE_TIME into v_row from student where student_id = 'S002';
  34. -- 打印输出
  35. DBMS_OUTPUT.PUT_LINE('日期:' || v_date || '姓名:' || v_name || ',' || v_row.STUDENT_NAME || ' 男生人数:' || v_man_sex || ' 地址:' || v_addr );
  36. end;

3、if 判断

统计总共有多少个学生,并进行if判断。

  1. declare
  2. -- 声明一个变量,记录有多少个学生
  3. v_student_count number;
  4. begin
  5. -- 给 v_student_count 变量赋值
  6. select count(*) into v_student_count from student;

  7. -- 执行if判断

  8. if v_student_count > 3 then
  9. DBMS_OUTPUT.PUT_LINE('当前学生数为: [' || v_student_count || ']>3');
  10. elsif v_student_count >=2 then
  11. DBMS_OUTPUT.PUT_LINE('当前学生数为: [' || v_student_count || '] in [2,3]');
  12. else
  13. DBMS_OUTPUT.PUT_LINE('当前学生数为: [' || v_student_count || ']<2');
  14. end if;
  15. end;

4、case

  1. -- case
  2. declare
  3. -- 声明一个变量,记录有多少个学生
  4. v_student_count number;
  5. begin
  6. -- 给 v_student_count 变量赋值
  7. select count(*) into v_student_count from student;

  8. -- 执行if判断

  9. case when v_student_count > 3 then
  10. DBMS_OUTPUT.PUT_LINE('当前学生数为: [' || v_student_count || ']>3');
  11. when v_student_count >=2 then
  12. DBMS_OUTPUT.PUT_LINE('当前学生数为: [' || v_student_count || '] in [2,3]');
  13. else
  14. DBMS_OUTPUT.PUT_LINE('当前学生数为: [' || v_student_count || ']<2');
  15. end case;
  16. end;

5、循环

输出1到100

1、loop 循环

  1. declare
  2. -- 定义一个变量并赋值
  3. v_count number := 1;
  4. begin
  5. loop
  6. -- 提出条件
  7. exit when v_count > 100;
  8. DBMS_OUTPUT.PUT_LINE('当前 count = ' || v_count);
  9. -- v_count 加1
  10. v_count := v_count + 1;
  11. end loop;
  12. end;

2、while 循环

  1. -- while 循环
  2. declare
  3. -- 定义一个变量并赋值
  4. v_count number := 1;
  5. begin
  6. while v_count <= 100 loop
  7. DBMS_OUTPUT.PUT_LINE('当前 count = ' || v_count);
  8. -- v_count 加1
  9. v_count := v_count + 1;
  10. end loop;
  11. end;

3、for循环

  1. -- for 循环
  2. declare
  3. -- 定义一个变量
  4. v_count number;
  5. begin
  6. for v_count in 1..100 loop
  7. DBMS_OUTPUT.PUT_LINE('当前 count = ' || v_count);
  8. end loop;
  9. end;

6、游标

1、无参数的游标

  1. -- 游标
  2. declare
  3. -- 声明一个游标
  4. cursor cur_student is select student_id,student_name,sex from student;
  5. -- 声明变量
  6. row_cur_student cur_student%rowtype;
  7. begin
  8. -- 打开游标
  9. open cur_student;

  10. -- 遍历数据
  11. loop
  12. -- 获取一行数据
  13. fetch cur_student into row_cur_student;
  14. -- 退出
  15. exit when cur_student%NOTFOUND;
  16. -- 执行业务逻辑(此句如果移动到exit when上方,则可能会多打印一句)
  17. DBMS_OUTPUT.PUT_LINE('studentId:' || row_cur_student.STUDENT_ID || ' studentName:' || row_cur_student.STUDENT_NAME);

  18. end loop;

  19. -- 关闭游标
  20. close cur_student;
  21. end;

2、带参数的游标

  1. declare
  2. -- 声明一个游标, 需要传递v_student_id参数
  3. cursor cur_student(v_student_id student.student_id%TYPE) is
  4. select student_id,student_name,sex from student where student_id = v_student_id;
  5. -- 声明变量
  6. row_cur_student cur_student%rowtype;
  7. -- 此变量通过查询获取值,然后带到游标中
  8. v_query_student_id student.student_id%TYPE;
  9. begin
  10. -- 打开游标
  11. --参数传递方式一: open cur_student('S001');

  12. -- 参数传递方式二:
  13. select 'S001' into v_query_student_id from dual;
  14. open cur_student(v_query_student_id);

  15. -- 遍历数据
  16. loop
  17. -- 获取一行数据
  18. fetch cur_student into row_cur_student;
  19. -- 退出
  20. exit when cur_student%NOTFOUND;
  21. -- 执行业务逻辑(此句如果移动到exit when上方,则可能会多打印一句)
  22. DBMS_OUTPUT.PUT_LINE('studentId:' || row_cur_student.STUDENT_ID || ' studentName:' || row_cur_student.STUDENT_NAME);

  23. end loop;

  24. -- 关闭游标
  25. close cur_student;
  26. end;

7、执行ddl dml

需要放到 execute immediate中执行,否则会报错。

  1. declare
  2. v_table_name varchar2(20) := 'student_bak';
  3. -- 拼接一个动态SQL
  4. v_sql varchar2(100);
  5. begin
  6. execute immediate 'create table student_bak as select * from student';
  7. execute immediate 'alter table student_bak add new_cloumn varchar2(20)';

  8. -- 带变量的执行
  9. v_sql := 'drop table ' || v_table_name;
  10. execute immediate v_sql;

  11. end;

8、存储过程

1、无参数的存储过程

  1. -- 无参数的存储过程
  2. create or replace procedure sp_print_all_student
  3. is
  4. -- 声明一个游标
  5. cursor c_all_student is select student_id,student_name from student;
  6. -- 声明一个变量
  7. row_student c_all_student%rowtype;
  8. begin
  9. -- 循环游标
  10. for row_student in c_all_student loop
  11. DBMS_OUTPUT.PUT_LINE(row_student.STUDENT_ID || ' ' || row_student.STUDENT_NAME);
  12. end loop;
  13. end;
  14. -- 调用
  15. begin
  16. SP_PRINT_ALL_STUDENT();
  17. end;

2、有输入输出参数的存储过程

  1. -- 有参数的存储过程
  2. create or replace procedure sp_find_student(/** 输入参数 */ i_student_id in student.student_id%TYPE,
  3. /** 输出参数 */ o_student_name out student.student_name%TYPE)
  4. IS
  5. -- 定义变量并赋值
  6. v_student_id varchar2(64) := i_student_id;
  7. begin
  8. DBMS_OUTPUT.PUT_LINE('v_student_id:' || v_student_id);
  9. -- 将查询到的 student_name 赋值到 o_student_name
  10. select student_name into o_student_name from student where student_id = i_student_id;
  11. end;

  12. declare
  13. -- 定义一个变量用于接收存储过程的返回值
  14. output_student_name student.student_name%TYPE;
  15. begin
  16. sp_find_student('S001', output_student_name);
  17. -- 输出存储过程的返回值
  18. DBMS_OUTPUT.PUT_LINE(output_student_name);
  19. end;

3、merge into 的使用

存在更新,不存在插入。

  1. create or replace procedure sp_merge_into(i_student_id in varchar2)
  2. IS
  3. begin
  4. -- 如果 using 中查询出来的数据,通过 on 条件匹配的话,则更新 student_bak表,否则插入student_bak表
  5. merge into STUDENT_BAK t
  6. using (select * from student where student_id = i_student_id) s
  7. on ( t.student_id = s.student_id )
  8. when matched then update set
  9. -- t.STUDENT_ID = s.STUDENT_ID, on中的条件不可更新
  10. t.STUDENT_NAME = s.STUDENT_NAME,
  11. t.SEX = s.SEX,
  12. t.CREATE_TIME = s.CREATE_TIME
  13. when not matched then insert(student_id, student_name, create_time) values (
  14. s.STUDENT_ID,
  15. s.STUDENT_NAME,
  16. s.CREATE_TIME
  17. );
  18. commit ;
  19. end;

4、测试异常

  1. create or replace procedure sp_error
  2. IS
  3. v_num number;
  4. begin
  5. DBMS_OUTPUT.PUT_LINE('测试异常');

  6. -- 产生异常
  7. v_num := 1 / 0;

  8. exception -- 存储过程异常
  9. when too_many_rows then
  10. dbms_output.put_line('返回值多于1行');
  11. when others then
  12. -- 异常处理方法,可以是打印错误,然后进行回滚等操作,下面操作一样,看自己情况决定
  13. rollback;
  14. dbms_output.put_line('错误码:' ||sqlcode);
  15. dbms_output.put_line('异常信息:' || substr(sqlerrm, 1, 512));
  16. end;

  17. begin
  18. sp_error();
  19. end;

5、bulk into & record

1、select into 中使用 bulk into & record

  1. create or replace procedure sp_bulk_collect_01
  2. IS
  3. -- 定义一个记录类型
  4. type STUDENT_INFO is record
  5. (
  6. student_id student.student_id%TYPE,
  7. student_name student.student_name%TYPE
  8. );

  9. -- 定义基于记录的嵌套表
  10. type nested_student_info is table of STUDENT_INFO;
  11. -- 声明变量
  12. student_list nested_student_info;
  13. begin
  14. -- 使用 bulk collect into 将所获取的结果集一次性绑定到记录变量 student_list 中
  15. select student_id,student_name bulk collect into student_list from student;

  16. -- 遍历
  17. for i in student_list.first .. student_list.last loop
  18. DBMS_OUTPUT.PUT_LINE('studentId:' || student_list(i).student_id || ' studentName:' || student_list(i).student_name);
  19. end loop;
  20. end;

  21. begin
  22. sp_bulk_collect_01;
  23. end;

2、fetch into 中使用 bulk into & forall

  1. -- bulk collect
  2. create or replace procedure sp_bulk_collect_02
  3. IS
  4. -- 定义一个游标
  5. cursor cur_student is select student_id,student_name,sex,create_time from student;
  6. -- 定义基于游标的嵌套表
  7. type nested_student_info is table of cur_student%rowtype;
  8. -- 声明变量
  9. student_list nested_student_info;
  10. begin
  11. -- 打开游标
  12. open cur_student;
  13. loop
  14. -- 一次获取2条数据插入到 student_list 中
  15. fetch cur_student bulk collect into student_list limit 2;
  16. -- 退出
  17. --exit when student_list%notfound; 不可使用这种方式
  18. exit when student_list.count = 0;

  19. -- 输出
  20. for i in student_list.first .. student_list.last loop
  21. DBMS_OUTPUT.PUT_LINE('studentId:' || student_list(i).student_id || ' studentName:' || student_list(i).student_name);
  22. end loop;

  23. -- 使用 forall 更新数据, 可以将多个dml语句批量发送给SQL引擎,提高执行效率。
  24. forall i in student_list.first .. student_list.last
  25. update student set student_name = student_list(i).STUDENT_NAME || '_update' where student_id = student_list(i).STUDENT_ID;
  26. commit ;
  27. end loop;

  28. -- 关闭游标
  29. close cur_student;
  30. end;

  31. begin
  32. sp_bulk_collect_02;
  33. end;

6、接收数组参数

  1. -- 创建StudentIdList数组的长度是4,每一项最多存20个字符
  2. create or replace type StudentIdList as varray(4) of varchar2(20);

  3. -- 创建存储过程,接收数组参数
  4. create or replace procedure sp_param_list(studentIdList in StudentIdList)
  5. is
  6. begin
  7. for i in 1..studentIdList.COUNT loop
  8. DBMS_OUTPUT.PUT_LINE('studentId:' || studentIdList(i));
  9. end loop;
  10. end;
  11. declare
  12. begin
  13. sp_param_list(STUDENTIDLIST('d','c','S001','S0021222222222233'));
  14. end;

7、接收数组对象,并将数组对象转换成表使用

  1. -- 创建数据库对象
  2. create or replace type StudentInfo is object(
  3. studentId varchar2(64),
  4. studentName varchar2(64)
  5. );
  6. -- 创建数组对象
  7. create or replace type StudentInfoArr as table of StudentInfo;

  8. -- 创建存储过程
  9. create or replace procedure sp_param_list_02(arr in StudentInfoArr)
  10. is
  11. -- 声明一个变量,记录传递进来的arr的数量
  12. v_student_count number := 0;
  13. begin
  14. -- 传递进来的数组转换成使用
  15. select count(*) into v_student_count from table(cast(arr AS StudentInfoArr))
  16. where studentId like 'S%';
  17. DBMS_OUTPUT.PUT_LINE('传递进来学生学号以S开头的学生有: ' || v_student_count || '个');

  18. -- 输出列表参数
  19. for i in 1..arr.COUNT loop
  20. DBMS_OUTPUT.PUT_LINE('studentId:' || arr(i).studentId || ' studentName:' || arr(i).studentName);
  21. end loop;
  22. end;

  23. declare
  24. begin
  25. sp_param_list_02(arr => StudentInfoArr(StudentInfo('S001','张三'),StudentInfo('S002','李四')));
  26. end;

8、返回多个参数

  1. create or replace procedure sp_return_value(stuInfoList out Sys_Refcursor)
  2. IS
  3. begin
  4. open stuInfoList for select STUDENT_ID,STUDENT_NAME,SEX from STUDENT;
  5. end;

  6. declare
  7. stu Sys_Refcursor;
  8. v_student_id STUDENT.STUDENT_ID%TYPE;
  9. v_student_name STUDENT.STUDENT_NAME%TYPE;
  10. v_sex STUDENT.SEX%TYPE;
  11. begin
  12. SP_RETURN_VALUE( stu);
  13. loop
  14. fetch stu into v_student_id,v_student_name,v_sex;
  15. exit when stu%notfound;
  16. DBMS_OUTPUT.PUT_LINE('studentId:' || v_student_id || ' studentName: ' || v_student_name);
  17. end loop;
  18. end;

9、程序包 package

1、定义包头

包头可以简单的理解Java中的接口。

  1. create or replace package pkg_huan as
  2. v_pkg_name varchar2(30) := 'pkg_huan';
  3. function add(param1 in number, param2 in number) return number;
  4. procedure sp_pkg_01;
  5. procedure sp_pkg_02(param1 in varchar2);
  6. end pkg_huan;

2、实现包体

包体可以简单的理解java中的实现接口的类。

  1. create or replace package body pkg_huan as
  2. -- 实现function
  3. function add(param1 in number, param2 in number) return number IS
  4. begin
  5. return param1 + param2;
  6. end;
  7. -- 实现无参数的存储过程
  8. procedure sp_pkg_01 as
  9. begin
  10. DBMS_OUTPUT.PUT_LINE('package name:' || v_pkg_name || 'procedure name: sp_pkg_01');
  11. end;
  12. -- 实现有参数的存储过程
  13. procedure sp_pkg_02(param1 in varchar2) as
  14. begin
  15. DBMS_OUTPUT.PUT_LINE('param1:' || param1);
  16. end;
  17. end;

3、调用包中的方法或存储过程

  1. begin
  2. -- 调用方法
  3. DBMS_OUTPUT.PUT_LINE('1+2=' || PKG_HUAN.add(1,2));
  4. -- 调用无参数的存储过程
  5. PKG_HUAN.sp_pkg_01();
  6. -- 调用有参数的存储过程
  7. PKG_HUAN.sp_pkg_02(12);
  8. end;

10、参考链接

1、http://www.cis.famu.edu/support/10g/Oracle_Database_10g/doc/appdev.102/b14261/objects.htm

Tags:oracle plsql if

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言