看到很多新手朋友想在存储过程或者匿名块中直接使用select * form table语句直接返回结果集,这样子是会提示错误的,因为PL/SQL块中不能用select 语句,而必须用select into。错误如下图
所以想要在块中返回结果集,可以使用游标进行遍历
set Serveroutput On
declare
v_empno emp.empno%type;
v_ename emp.ename%type;
v_salary emp.sal%type;
cursor emp_cursor is
select empno,ename,sal from emp where deptno = 20;
begin
open emp_cursor;
loop
fetch emp_cursor into v_empno,v_ename,v_salary;
exit when emp_cursor%notfound;
dbms_output.put_line('编号为'||v_empno||'的员工名字为'||v_ename
||',他的薪资为'
||v_salary);
end loop;
close emp_cursor;
end;
我这里只是截取了emp表中的某几个字段,也可以直接设置emp类型的游标值存储变量,输出完整的结果集。
有同学可能会想到用动态SQL语句
DECLARE
V_SQLSTMT VARCHAR2(300);
BEGIN
V_SQLSTMT := 'SELECT * FROM emp WHERE empno = 7396';
EXECUTE IMMEDIATE V_SQLSTMT;
END;
实践一下就能知道,这段代码是可以编译成功的,然而它并不会输出任何结果。
也就是说即使使用动态SQL语句,也需要用到游标。
set Serveroutput On
DECLARE
type emp_cursor is ref cursor;
emp_cur emp_cursor;
v_empno emp.empno%type;
v_ename emp.ename%type;
BEGIN
open emp_cur for
'select empno,ename from emp where deptno = 20';
loop
fetch emp_cur into v_empno,v_ename;
exit when emp_cur%notfound;
Dbms_Output.Put_Line(v_empno||' '||v_ename);
end loop;
close emp_cur;
END;
可以看到动态语句中使用open for进行遍历。
需要注意的是,动态SQL语句中的execute immediate只能处理单行查询(如上上段代码),如果想不通过游标进行遍历,同时想用execute immediate动态语句,就必须要用批量绑定bulk collect into。这样execute immediate就有了处理多行查询的功能。因为是批量绑定,需要把查询出的这么多结果放到索引表中。