Oracle-包的创建和使用(游标的简单使用,临时表,动态 sql)

2019年07月23日 16:02 · 阅读(483) ·

[目录]

参考

Oracle 参照游标(SYS_REFCURSOR)使用

ORACLE中%TYPE和%ROWTYPE的使用

测试表-test_v_hwhao1

测试数据

例子1-无参

新建包说明

  1. CREATE OR REPLACE PACKAGE P_Test_Update IS
  2. /* =============================================
  3. * PROCEDURE:
  4. * update_table_test_v_hwhao1_opdate
  5. * DESCRIPTION:
  6. * 更行表 test_v_hwhao1 的 opdate 时间
  7. * ARGUMENT:
  8. * RETURN:
  9. *
  10. * HISTORY:
  11. * =============================================*/
  12. PROCEDURE update_table_opdate;
  13. END P_Test_Update;

查看创建结果

新建包体

  1. CREATE OR REPLACE PACKAGE BODY P_Test_Update IS
  2. /* =============================================
  3. * PROCEDURE:
  4. * update_table_test_v_hwhao1_opdate
  5. * DESCRIPTION:
  6. * 更行表 test_v_hwhao1 的 opdate 时间
  7. * ARGUMENT:
  8. * RETURN:
  9. *
  10. * HISTORY:
  11. * =============================================*/
  12. PROCEDURE update_table_opdate IS
  13. --定义游标
  14. CURSOR test_v_hwhao1_cursor IS
  15. SELECT * FROM test_v_hwhao1;
  16. --定义变量 opdate,并赋值当前时间
  17. --opdate date := sysdate;
  18. --开始
  19. BEGIN
  20. --循环读取游标数据
  21. FOR item in test_v_hwhao1_cursor LOOP
  22. update test_v_hwhao1 t set t.opdate = sysdate where t.no = item.no;
  23. END LOOP;
  24. END update_table_opdate;
  25. END P_Test_Update;

查看创建结果

扩展

包说明和包体同时在一个 sql 中创建,中间需要加 /,否则会报错,具体参考

Oracle-已编译但有错误

调用

  1. --调用
  2. begin
  3. -- Call the procedure
  4. p_test_update.update_table_opdate;
  5. end;

查看测试结果

  1. --查询更新结果
  2. select * from test_v_hwhao1

结果:

例子2-存储过程有入参,出参

创建包说明

  1. CREATE OR REPLACE PACKAGE P_Test_Calc IS
  2. /*****************************************************************************************************************/
  3. -- 存储过程: 删除临时表
  4. -- 参数说明: IN_TABLE_NAME(临时表名称)
  5. /*****************************************************************************************************************/
  6. PROCEDURE PRO_DROP_TABLE(IN_TABLE_NAME IN VARCHAR2);
  7. /*****************************************************************************************************************/
  8. -- 存储过程: 把数据添加到临时表,并返回数据
  9. -- 参数说明:
  10. -- IN_TABLE_NAME(临时表名称)
  11. -- OUT_CALC_RESULT(返回结果集)
  12. /*****************************************************************************************************************/
  13. PROCEDURE PRO_CALC_TABLE(IN_TABLE_NAME IN VARCHAR2, OUT_CALC_RESULT OUT SYS_REFCURSOR);
  14. END P_Test_Calc;

创建包体

  1. CREATE OR REPLACE PACKAGE BODY P_Test_Calc IS
  2. /*****************************************************************************************************************/
  3. -- 存储过程: 删除临时表
  4. -- 参数说明: IN_TABLE_NAME(临时表名称)
  5. /*****************************************************************************************************************/
  6. PROCEDURE PRO_DROP_TABLE(IN_TABLE_NAME IN VARCHAR2) IS
  7. VAR_NUM NUMBER;
  8. BEGIN
  9. SELECT COUNT(1) INTO VAR_NUM FROM USER_TABLES WHERE TABLE_NAME = UPPER(IN_TABLE_NAME);
  10. IF VAR_NUM > 0 THEN
  11. EXECUTE IMMEDIATE 'DROP TABLE ' || IN_TABLE_NAME;
  12. END IF;
  13. END PRO_DROP_TABLE;
  14. /*****************************************************************************************************************/
  15. -- 存储过程: 把数据添加到临时表,并返回数据
  16. -- 参数说明:
  17. -- IN_TABLE_NAME(临时表名称)
  18. -- OUT_CALC_RESULT(返回结果集)
  19. /*****************************************************************************************************************/
  20. PROCEDURE PRO_CALC_TABLE(IN_TABLE_NAME IN VARCHAR2, OUT_CALC_RESULT OUT SYS_REFCURSOR) IS
  21. VAR_STR_SQL VARCHAR2(4000); --SQL语句
  22. BEGIN
  23. --1、创建返回数据的临时表
  24. PRO_DROP_TABLE(IN_TABLE_NAME); --先删除临时表
  25. VAR_STR_SQL := 'CREATE GLOBAL TEMPORARY TABLE '||IN_TABLE_NAME||' (NO VARCHAR2(500), NAME VARCHAR2(500)) ON COMMIT DELETE ROWS';
  26. EXECUTE IMMEDIATE VAR_STR_SQL;
  27. --2、根据指标类型,获取并遍历计算指标数据
  28. FOR Q IN (SELECT * FROM test_v_hwhao1 T WHERE T.NO > 1)
  29. LOOP
  30. --将结果插入到临时表中
  31. VAR_STR_SQL := 'INSERT INTO ' ||IN_TABLE_NAME|| ' VALUES(''' ||Q.NO|| ''',''' ||Q.NAME|| ''')';
  32. EXECUTE IMMEDIATE VAR_STR_SQL;
  33. END LOOP;
  34. --3、将临时表数据赋值返回
  35. VAR_STR_SQL := 'SELECT * FROM ' ||IN_TABLE_NAME;
  36. OPEN OUT_CALC_RESULT FOR VAR_STR_SQL;
  37. END PRO_CALC_TABLE;
  38. END P_Test_Calc;

调用-使用 PL\SQL

这里留个坑,目前还没找到直接使用 sql 测试的方法,我是使用查看包体的方式来测试的。

查看包体内容

右键测试

运行测试

运行没有报错

删除包

  1. --删除
  2. drop package body P_Test_Calc;
  3. drop package P_Test_Calc;

调用-使用 sql 调用测试并查看结果

不指定参数

2019年7月23日16:02:16
这里留个坑,希望通过直接使用 sql 调用对应包,并通过返回参数查看数据。

2019年9月9日-填坑

  1. declare
  2. --定义一个游标变量
  3. Out_Calc_Result sys_refcursor;
  4. --定义一个表示表中一行记录的变量
  5. Item test_v_hwhao1%rowtype;
  6. --临时表名称
  7. In_Table_Name VARCHAR2(30) := 'test_v_hwhao1_temp';
  8. begin
  9. --调用存储过程创建临时表,添加数据
  10. P_Test_Calc.PRO_CALC_TABLE(In_Table_Name,Out_Calc_Result);
  11. --读取游标
  12. loop
  13. fetch Out_Calc_Result into Item.NO, Item.NAME;
  14. --游标没有数据,退出循环
  15. exit when Out_Calc_Result%notfound;
  16. --输出临时表数据
  17. dbms_output.put_line(Item.NO||'-'||Item.NAME);
  18. end loop;
  19. --删除临时表
  20. P_Test_Calc.PRO_DROP_TABLE(In_Table_Name);
  21. end;

输出

  1. 2-0
  2. 3-理想的生活是排除T
  3. 5-想到一百年后无少T
  4. 6-我想有人能理解我T
  5. 4-睡到二三更时凡荣T
  6. 10-测试老大哥
  7. 11-测试老大哥-11
  8. 7-老大哥T-T
  9. 8-小老弟T
  10. 9-99T

指定参数

  1. declare
  2. --定义一个游标变量
  3. Out_Calc_Result sys_refcursor;
  4. --定义一个表示表中一行记录的变量
  5. Item test_v_hwhao1%rowtype;
  6. --临时表名称
  7. In_Table_Name VARCHAR2(30) := 'test_v_hwhao1_temp';
  8. begin
  9. --调用存储过程创建临时表,添加数据
  10. P_Test_Calc.PRO_CALC_TABLE(OUT_CALC_RESULT => Out_Calc_Result,IN_TABLE_NAME => In_Table_Name);
  11. --读取游标
  12. loop
  13. fetch Out_Calc_Result into Item.NO, Item.NAME;
  14. --游标没有数据,退出循环
  15. exit when Out_Calc_Result%notfound;
  16. --输出临时表数据
  17. dbms_output.put_line(Item.NO||'-'||Item.NAME);
  18. end loop;
  19. --删除临时表
  20. P_Test_Calc.PRO_DROP_TABLE(In_Table_Name);
  21. end;

输出

  1. 2-0
  2. 3-理想的生活是排除T
  3. 5-想到一百年后无少T
  4. 6-我想有人能理解我T
  5. 4-睡到二三更时凡荣T
  6. 10-测试老大哥
  7. 11-测试老大哥-11
  8. 7-老大哥T-T
  9. 8-小老弟T
  10. 9-99T