一、游标定义
1.游标是查询结果集的平面化展示,通过游标方便定位到结果集中某个特定的行。 2.游标的分类 显示游标:即用户自定义游标,专门用于处理select语句返回的多行数据 隐式游标:系统自动定义的游标,记录集只有单行数据,用于处理select into 和DML语句 3.游标使用的一般过程: 显示游标:声明, 打开, 读取, 关闭 隐式游标:直接使用读取,声明、打开、关闭都是系统自动进行的 4显示游标的过程描述 a.声明游标 CURSOR cursor_name IS select_statement 如:CURSOR emp_cur IS SELECT empno,ename,job,sal FROM scott.emp; b.打开游标,打开游标则执行对应的select语句,将对应的结果集存放到游标当中 OPEN cursor_name c.获取数据,提取单行数据,需要配合循环语句来使用,提取多行数据,collect为集合变量 FETCH cursor_name INTO var_name1,...var_name2 ; FETCH cursor_name BULK COLLECT INTO collect1,collect2,...[LIMIT rows]; d.关闭游标 CLOSE cursor_name 5.显示游标的5个属性 cursor_name%ISOPEN --游标是否打开 cursor_name%FOUND --最近的FETCH是否提取到数据 cursor_name%NOTFOUND --最近的FETCH是否没有提取到数据 cursor_name%ROWCOUNT --返回到目前为止,已经从游标缓冲区中提取到数据的行数 二、游标使用 1.输入job,输出ename,sal值 declare v_name emp.ename%type; v_sal emp.sal%type; cursor cur_one is select ename,sal from emp where job ='&input'; begin open cur_one; dbms_output.put_line('ename sal'); loop fetch cur_one into v_name,v_sal; exit when (cur_one%notfound); dbms_output.put_line(v_name||' '||v_sal); end loop; close cur_one; end; 2.使用游标统一定义变量类型 declare cursor cur_one is select ename,sal,job,mgr,hiredate,comm from emp where job ='&input'; v_cur_col cur_one%rowtype; begin open cur_one; dbms_output.put_line('ename sal'); loop fetch cur_one into v_cur_col; exit when (cur_one%notfound); dbms_output.put_line(v_cur_col.ename||' '||v_cur_col.sal); end loop; close cur_one; end; 3.游标FOR循环 游标FOR循环是为了简化游标使用过程而设计的。使用游标FOR循环检索游标时,游标的打开、数据提取、数据是否检 索到的判断与游标的关闭都是ORACLE系统自动进行的。 --显式 DECLARE CURSOR CURSOR_006 IS SELECT ENAME, HIREDATE FROM EMP WHERE SAL < &SAL; BEGIN DBMS_OUTPUT.PUT_LINE('ename hiredate'); FOR V_CUR IN CURSOR_006 LOOP DBMS_OUTPUT.PUT_LINE(V_CUR.ENAME || ' ' || V_CUR.HIREDATE); END LOOP; END; --隐式 BEGIN DBMS_OUTPUT.PUT_LINE('ename hiredate'); FOR V_CUR IN (SELECT ENAME, HIREDATE FROM EMP WHERE SAL < &SAL) LOOP DBMS_OUTPUT.PUT_LINE(V_CUR.ENAME || ' ' || V_CUR.HIREDATE); END LOOP; END; 三、记录 是一个或多个字段且拥有数据类型的集合体,类似于表的数据结构,定义了PL/SQL记录类型之后,可以定义 PL/SQL记录变量,多用于简化单行多列的数据处理。 1.记录的定义 a.自定义记录成员 TYPE TYPE_NAME IS RECORD (field_name1 datatype1 [NOT NULL] [ := DEFAULT EXPRESSION], field_name2 datatype2 [NOT NULL] [ := DEFAULT EXPRESSION], ... field_nameN datatypeN [NOT NULL] [ := DEFAULT EXPRESSION]); record_name TYPE_NAME; b.参照数据对象定义 record_name table_name%rowtype record_name view_name%rowtype reocrd_name cursor_name%rowtype 四、记录的使用 1.使用记录及记录成员 undefine no DECLARE TYPE emp_record_type IS RECORD ( name emp.ename%TYPE, salary emp.sal%TYPE, dno emp.deptno%TYPE ); emp_record emp_record_type; BEGIN SELECT ename, sal, deptno INTO emp_record --[select ename,sal into emp_record.name,emp_record.salary] FROM emp WHERE empno = &no; dbms_output.put_line(emp_record.name); --输出时仅仅输出记录变量的一个成员emp_record.name END; 2.使用PL/SQL记录(记录成员)变量 DECLARE dept_record dept%ROWTYPE; BEGIN dept_record.deptno := 50; dept_record.dname := 'ADMINISTRATOR'; dept_record.loc := 'BEIJING'; INSERT INTO dept VALUES dept_record; END; 3.记录使用的几个问题 a.记录成员非空时必须在定义时给初值 DECLARE TYPE ex_type IS RECORD (col1 NUMBER(3), col2 VARCHAR2(5) NOT NULL); --编译不通过 ex_record ex_type; BEGIN ex_record.col1:=15; ex_record.col1:=TO_CHAR(ex_record.col1); ex_record.col2:='John'; DBMS_OUTPUT.PUT_LINE('ex_record.col1 is '||ex_record.col1); DBMS_OUTPUT.PUT_LINE('ex_record.col2 is '||ex_record.col2); END; DECLARE TYPE ex_type IS RECORD( col1 NUMBER(3), col2 VARCHAR2(5) NOT NULL := 'John'); ex_record ex_type; BEGIN ex_record.col1 := 15; ex_record.col1 := TO_CHAR(ex_record.col1); ex_record.col2:='TOM';--可以赋新值 DBMS_OUTPUT.PUT_LINE('ex_record.col1 is ' || ex_record.col1); DBMS_OUTPUT.PUT_LINE('ex_record.col2 is ' || ex_record.col2); END; b.来自不同的记录类型的记录变量之间不能相互赋值 c.同一个记录的记录变量之间可以相互赋值 d.基于表,游标,自定义记录的使用 DECLARE CURSOR dept_cur IS SELECT * FROM dept WHERE deptno = 30; TYPE dept_type IS RECORD( deptno NUMBER(2), dname VARCHAR2(14), loc VARCHAR2(13)); dept_rec1 dept%ROWTYPE; --声明基于表dept的记录变量 dept_rec2 dept_cur%ROWTYPE; --声明基于游标dept_cur的记录变量 dept_rec3 dept_type; --声明基于自定义dept_type的记录变量 BEGIN SELECT * INTO dept_rec1 FROM dept WHERE deptno = 30; OPEN dept_cur; LOOP FETCH dept_cur INTO dept_rec2; EXIT WHEN dept_cur%NOTFOUND; END LOOP; dept_rec1 := dept_rec2; dept_rec3 := dept_rec2; DBMS_OUTPUT.PUT_LINE(dept_rec1.deptno || ' ' || dept_rec1.dname); DBMS_OUTPUT.PUT_LINE(dept_rec2.deptno || ' ' || dept_rec2.dname); DBMS_OUTPUT.PUT_LINE(dept_rec3.deptno || ' ' || dept_rec3.dname); END;