oracle游标(Oracle 嵌套游标的威力:实现复杂查询)
一、oracle用游标分页查询学生所有信息
Oracle内分页:
1.首先创建返回结果集的包,代码如下:
--创建包
create or replace package types as
type cursorType is ref cursor;
end;12341234
2.创建实现分页查询的存储过程:
--创建存储过程
CREATE OR REPLACE PROCEDURE PROC_GET_DATA_PAGING(P_TABLENAME IN VARCHAR2,--表(视图)名
P_STRWHERE IN VARCHAR2,--查询条件
P_ORDERCOLUMN IN VARCHAR2,--排序的列
P_CURPAGE IN OUT NUMBER,--当前页
P_PAGESIZE IN OUT NUMBER,--每页显示记录条数
P_TOTALRECORDS OUT NUMBER,--总记录数
P_TOTALPAGES OUT NUMBER,--总页数
V_CUR OUT TYPES.CURSORTYPE)--返回的结果集
IS
V_SQL VARCHAR2(4000):='';--SQL语句
V_STARTRECORD NUMBER(10);--开始显示的记录条数
V_ENDRECORD NUMBER(10);--结束显示的记录条数
V_SHOWALL INTEGER;--是否显示全部记录
BEGIN
--记录中总记录条数
V_SQL:='SELECT TO_NUMBER(COUNT(*)) FROM'|| P_TABLENAME||
' WHERE 1=1';
IF P_STRWHERE IS NOT NULL OR P_STRWHERE<>'' THEN
V_SQL:= V_SQL|| P_STRWHERE;
END IF;
EXECUTE IMMEDIATE V_SQL
INTO P_TOTALRECORDS;
--验证页面记录大小
IF P_PAGESIZE<= 0 THEN
V_SHOWALL:= 1;
P_PAGESIZE:= 0;
END IF;
IF V_SHOWALL IS NULL THEN
--根据页大小计算总页数
IF MOD(P_TOTALRECORDS, P_PAGESIZE)= 0 THEN
P_TOTALPAGES:= TRUNC(P_TOTALRECORDS/ P_PAGESIZE, 0);
ELSE
P_TOTALPAGES:= TRUNC(P_TOTALRECORDS/ P_PAGESIZE, 0)+ 1;
END IF;
ELSE
P_TOTALPAGES:= 1;
END IF;
--验证页号
IF P_CURPAGE< 1 THEN
P_CURPAGE:= 1;
END IF;
IF P_CURPAGE> P_TOTALPAGES THEN
P_CURPAGE:= P_TOTALPAGES;
END IF;
--实现分页查询
V_STARTRECORD:=(P_CURPAGE- 1)* P_PAGESIZE+ 1;
V_ENDRECORD:= P_CURPAGE* P_PAGESIZE;
V_SQL:='SELECT* FROM(SELECT A.*, ROWNUM R FROM'||
'(SELECT* FROM'|| P_TABLENAME;
IF P_STRWHERE IS NOT NULL OR P_STRWHERE<>'' THEN
V_SQL:= V_SQL||' WHERE 1=1'|| P_STRWHERE;
END IF;
IF P_ORDERCOLUMN IS NOT NULL OR P_ORDERCOLUMN<>'' THEN
V_SQL:= V_SQL||' ORDER BY'|| P_ORDERCOLUMN;
END IF;
IF V_SHOWALL IS NULL THEN
V_SQL:= V_SQL||') A WHERE ROWNUM<='|| V_ENDRECORD||
') B WHERE R>='|| V_STARTRECORD;
ELSE
V_SQL:= V_SQL||') A) B';
END IF;
DBMS_OUTPUT.PUT_LINE(V_SQL);
OPEN V_CUR FOR V_SQL;
END PROC_GET_DATA_PAGING;123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
一定要先创建返回结果集的包,否则编译存储过程有问题。
二、oracle 怎么提升游标速度
游标一般都是在执行sql语句,我不知道你指的是这个sql语句比较慢,还是单纯的游标速度慢。
sql语句慢可以根据使用改写sql语句的写法,建立索引,建立分区等优化手段来解决。
单纯游标速度慢,可以考略批量执行
bulk collect这种方式提取数据
使用forall替代for循环也可以提升效率。
以下是我总结的plsql调优的重点,你可以参考一下:
1.尽早退出循环
2. static的变量尽量放在循环的外层
3.因为and和or只要判断左边的表达式为真即可推出逻辑判断
所以
将容易出现true的逻辑表达式放在左边,这样可以省下处理的时间
4. if else和case when同上
5.尽量使用迭代,而不是递归,因为调用存储过程或者函数,会开辟另外的内存空间
6.通常函数都是值传递,即传参数的时候会copy参数的值到子程序中
对于数据量比较大的参数可以使用
in out nocopy指定引用传递,可以节省大量时间
7.可以使用关联数组,较少查找集合中元素的时间
关联数组
index by varchar2(xx)类似于map,会省下很集合操作,以及时间。
8.对于cpu密集型的plsql,可以使用native本地编译的特性
alter xxx compile plsql_code_type=native;
9.经常使用的子程序可以使用inline函数内嵌到主程序中
pragma inline($FUNCTION_NAME,'yes');
重载的程序只要拥有相同的名称都会被内嵌到program unit中
plsql_optimize_level=2的时候需要声明inline使用内联
plsql_optimize_level=3的编译的时候会自动的做这部分工作。不需要自己执行inline操作。可以使用PRAGMA INLINE(p1,'NO');禁止内联
当level=3的时候声明了inline会给予这个子程序更高的inline的优先级。
下面的语句中
(1)PRAGMA INLINE(p1,'YES');
(2)PRAGMA INLINE(p1,'NO');
(3)PRAGMA INLINE(p1,'YES');
第二行会覆盖第一行以及第三行,也就是说program unit中奖不使用内联
10.大量数字操作的时候可以使用java存储过程
11.使用result cache功能缓存经过计算得到的结果
relies_on($TB_NAME)
指定当表tb_name的数据改变时,结果集缓存失效
12.使用
update of$COLUMN_NAME on$TB_NAME
for each row
when(new.xx>1000)
可以省下需要处理时间
最好都使用after触发器,before可能会有锁定的问题
三、oracle 定义存储过程的时候,能不能循环定义多个游标
oracle没有游标数组的概念。但是你可以定义动态游标,举个例子:
declare
bm number;
zw varchar2(10);
tt number;
str varchar2(50);
type cur_type is ref cursor;--定义游标类型
cur cur_type;--定义游标变量
begin
str:='select deptno,sum(sal) from emp group by deptno';--查询字符串
open cur for str;
dbms_output.put_line('每个部门的工资总和:');
while cur%found loop
dbms_output.put_line(bm||''||tt);
fetch cur into bm,tt;
end loop;
str:='select job,avg(sal) from emp group by job';--查询字符串
open cur for str;
dbms_output.put_line('每个职位的工资总和:');
fetch cur into zw,tt;
while cur%found loop
dbms_output.put_line(zw||''||tt);
fetch cur into zw,tt;
end loop;
end;
每次通过改变str的值,来改变select语句,从而改变游标。
至于循环游标就是这样:
open cur for str;--打开游标
dbms_output.put_line('每个职位的工资总和:');
fetch cur into zw,tt;
while cur%found loop--循环
dbms_output.put_line(zw||''||tt);
fetch cur into zw,tt;
end loop;--循环结束