背景:
本人小小实习生,oracle小白,,刚刚接触oracle的plsql块。记录下来这个学习过程,有错麻烦各位指出。
情景:
通过遍历查询一个表的结果集,得到结果集中每行结果中的其中一个字段的值,作为另一个查询的where语句查询条件。
之前的解决方案是在service层中遍历第一次查询的结果集,然后在这个遍历过程中多次调用第二个查询的方法,这就导致了在控制层和业务逻辑层只需要一个方法,但到了数据交换层需要分开为两个方法,很繁琐。恰巧之前有了解到oracle中可以通过存储函数实现这个功能,所以学习了下plsql块。
预备知识:
1.plsql代码块基本语法:
DECLARE
--这里声明一些变量②和游标 ③
BEGIN
--需要执行的逻辑 包括一些游标遍历
EXCEPTION
--发生异常的逻辑
END;
2.Oracle中变量类型
这里我就列举下我目前使用到
NUMBER(p,s) 数值类型 p表示精度 s表示小数长度
例如 NUMBER(3,2) 表示的是 整数部分最大是1位,小数部分是2位的数
NUMBER等同于NUMBER(5)
INT
VARCHAR
CHAR
表%ROWTYPE 例如 emp表中有 id,name,dept 三个字段, emp_row emp%ROWTYPE ,变量emp_row 同样有 id,name,dept三个字段。
表.字段%TYPE 例如 emp.id 是number类型的, emp_id emp.id%type 则表示变量emp_id和emp表的id字段是相同的。
3.Oracle游标
参考 http://www.iteye.com/topic/649874
游标的概念:游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。
游标的作用:用于临时存储从数据库中提取的数据块。
我将游标理解为java中jdbc中的resultset 对象,相当于一个记录查询结果的虚拟表,如果想拿到其中的数据需要遍历。
游标的应用:
属性:
SQL%FOUND FETCH有结果则为true
SQL%NOTFOUND FETCH无结果为true
SQL%ISOPEN 游标打开为true
SQL%ROWCOUNT 返回当前记录在游标中的行数
隐式游标
默认起名字SQL,不用我们开启也不用关闭.DML语句会自动生成隐式游标,主要起到程序控制的作用。
显示游标
声明方式: CURSOR mycursor IS select * from emp where id >5; 查询结果将会记录到游标 mycursor中
REF游标(动态游标)
//TODO
游标的遍历方式
FOR i IN mycursor LOOP --这种方式会自动打开游标和关闭游标,因此务必不要重复打开,我出现过错误。
DBMS_OUTPUT.PUTLINE(i.id||i.name||i.dept); --i就有点类似于foreach 中的那个变量
END LOOP;
OPEN mycursor;
LOOP
FETCH mycursor INTO rs; --FETCH类似java中iterator遍历集合的next() 即拿到了下一个元素同时将迭代指针指向下下个元素
EXIT WHEN mycursor%NOTFOUND;
END LOOP;
解决的问题:
根据产品id去查询改产品有几种颜色类型,遍历这些颜色类型,每一个颜色类型找到一张图片及一些其它相关的数据。总共需要查询三个表
code:
declare
v_pid product.id%type default 877594; --为了以后学习存储函数做准备,这里设置默认值
cursor colorlist is
select color_type from productpic where productid=v_pid group by color_type;
v_colorid productpic.color_type%type;
cl_id int;
cursor v_result is
select * from(
select p.cmsimage imageurl,
p.productid pid,
p.type imagetypeid,
p.color_type colorid,
c.color_name colorname,
c.code colorcode,
pt.name imagetypename,
p.priority pr,
pt.priority priority,
p.id imageid
from productpic p,catalog_imagecolor c,productpic_type pt
where p.productid = v_pid
and p.color_type = cl_id
and p.type in(0,11)
and p.color_type = c.id
and p.type = pt.id
order by p.priority
)where rownum=1;
begin
for cl in colorlist loop --遍历第一个游标 在游标遍历过程中遍历第二个游标
if cl.color_type<>0 then
-- dbms_output.put_line('current colorid: '||cl.color_type);
cl_id :=cl.color_type;
if v_result%isopen then
close v_result;
end if;
for rs in v_result --遍历第二个游标
loop
dbms_output.put_line('current imageurl: '||rs.imageurl);
end loop ;
end if;
end loop;
exception
when others then
dbms_output.put_line('error!');
end;
通过plsql可以看出,原先需要在业务逻辑层做的判断和数据交换层分成两个方法的麻烦事,实际上在oracle中只需要写到一个存储函数中就可以解决, 同时也方便之后的维护和调用。
第一次写博客,希望自己能坚持下去。