码迷,mamicode.com
首页 > 其他好文 > 详细

游标(学习笔记)

时间:2015-01-08 14:50:37      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:

--游标分2种类型:
--静态游标:结果集已经存在(静态定义)的游标,分为隐式和显示游标
--隐式游标:所有DML语句为隐式游标,通过隐式游标属性可以获取SQL语句信息
--显示游标:用户显示声明的游标,即指定结果集,当查询返回结果超过一定行时,就需要一个显示游标
--REF 游标:动态关联结果集的临时对象
-强类型:带return类型
-弱类型: 不带return类型

--隐式游标
--在PL/SQL中编写的每条SQL 语句实际上都是隐匿游标。通过在DML操作后使用SQL%ROWCOUNT属性,可以
--知道语句所改变的行数(INSERT ,UPDATE,DELETE)返回理新行数,SELECT 返回查询行数.

--显示游标
--语法:CURSOR 游标名称 ([参数列表,]) [RETURN 返回值类型]
IS 子查询(SELECT _statement)
--第一步:声明游标:
CURSOR 游标名 IS SELECT 。。使用CURSOR定义
--第二步:打开游标
使用OPEN
OPEN 游标名
--第三步:提取游标
使用FETCH 游标 INTO 变量
--第四步:关闭游标
CLOSE 游标名
--显式游标属性:
%FOUND 找到是否找到数据,有数据TRUE,没有则FALSE
%ISOPEN 判断游标是否打开,打开则返回TRUE,没有打开则返回FALSE
%NOTFOUND 返回FETCH ...INTO...是否有数据如果没有返回TRUN,有则为FALSE
%ROWCOUNT 返回执行FETCH 语句所返回的行数,初始为0,每执行一行则%ROWCOUNT增加1
--隐式游标属性:
SQL%FOUND 找到是否找到数据,有数据TRUE,没有则FALSE
SQL%ISOPEN 判断游标是否打开,打开则返回TRUE,没有打开则返回FALSE
SQL%NOTFOUND 返回FETCH ...INTO...是否有数据如果没有返回TRUN,有则为FALSE
SQL%ROWCOUNT 返回执行FETCH 语句所返回的行数,初始为0,每执行一行则%ROWCOUNT增加1

隐式游标:

--验证SQL%ROWCOUNT

DECLARE
  v_count         NUMBER;
BEGIN
  SELECT COUNT(*) INTO v_count FROM dept; --只返回一行结果
  dbms_output.put_line(SQL%ROWCOUNT= || SQL%ROWCOUNT);
END;

结果:SQL%ROWCOUNT= 1

--验证SLQ%ROWCOUNT并返回行数

DECLARE
BEGIN
   INSERT INTO dept(deptno,dname,loc)VALUES(90,qqqq,北京);
     dbms_output.put_line(SQL%ROWCOUNT= || SQL%ROWCOUNT);
END;

结果:SQL%ROWCOUNT= 1

--单行隐式游标

DECLARE
   v_empRow         emp%ROWTYPE;
BEGIN
  SELECT * INTO v_empRow FROM emp WHERE empno=7369;
  IF SQL%FOUND THEN   --发现数据
    dbms_output.put_line(员工姓名: || v_empRow.ename||职位: ||v_empRow.job);
    END IF;
END;

结果:员工姓名: SMITH职位: CLERK

--多行隐式游标

DECLARE
BEGIN
  UPDATE EMP SET SAL = SAL * 1.2;
  IF SQL%FOUND THEN
    --发现数据
    DBMS_OUTPUT.PUT_LINE(更新行数 || SQL%ROWCOUNT);
  ELSE
    DBMS_OUTPUT.PUT_LINE(更新行数 || SQL%ROWCOUNT);
  END IF;
END;

结果:更新行数14

--显示游标
--定义游标例1:

DECLARE
 CURSOR emp_cur IS
 SELECT empno,ename FROM emp;                    --定义游标
 v_id     emp.empno%TYPE;              --定义变量ID
 v_name    emp.ename%TYPE;
BEGIN
  OPEN emp_cur ;                          --打开游标
  FETCH emp_cur INTO v_id,v_name;    ---提示取游标
  LOOP
    EXIT WHEN emp_cur%notFOUND;                     --判断是否还有数据
    dbms_output.put_line(员工编号||v_id||,员工姓名:||v_name);
    FETCH emp_cur INTO v_id,v_name;    ---提示取游标
  END LOOP;
  CLOSE emp_cur;                  --关闭游标
END;

结果:

员工编号7369,员工姓名:SMITH
员工编号7499,员工姓名:ALLEN
员工编号7521,员工姓名:WARD
员工编号7566,员工姓名:JONES
员工编号7654,员工姓名:MARTIN
员工编号7698,员工姓名:BLAKE
员工编号7782,员工姓名:CLARK
员工编号7788,员工姓名:SCOTT
员工编号7839,员工姓名:KING
员工编号7844,员工姓名:TURNER
员工编号7876,员工姓名:ADAMS
员工编号7900,员工姓名:JAMES
员工编号7902,员工姓名:FORD
员工编号7934,员工姓名:MILLER

--定义游标例2:

DECLARE
  V_NAME  VARCHAR2(50); --定义变量姓名
  V_DNAME VARCHAR2(50); --定义变量部门名称
  CURSOR CUR_E IS --定义游标
    SELECT ENAME, DNAME FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;
BEGIN
  OPEN CUR_E; --打开游标
  LOOP
    --使用循环来读取游标
    FETCH CUR_E
      INTO V_NAME, V_DNAME; --提取游标
    EXIT WHEN CUR_E%NOTFOUND; --判断游标是否还有内容
    DBMS_OUTPUT.PUT_LINE(CUR_E%ROWCOUNT ||   员工姓名: || V_NAME ||  部门名称: ||
                         V_DNAME);                            --输出内容
  
  END LOOP;
  CLOSE CUR_E; --关闭游标
END;

结果:

程序结果:
1  员工姓名:SMITH 部门名称:RESEARCH
2  员工姓名:ALLEN 部门名称:SALES
3  员工姓名:WARD 部门名称:SALES
4  员工姓名:JONES 部门名称:RESEARCH
5  员工姓名:MARTIN 部门名称:SALES
6  员工姓名:BLAKE 部门名称:SALES
7  员工姓名:CLARK 部门名称:ACCOUNTING
8  员工姓名:SCOTT 部门名称:RESEARCH
9  员工姓名:KING 部门名称:ACCOUNTING
10  员工姓名:TURNER 部门名称:SALES
11  员工姓名:ADAMS 部门名称:RESEARCH
12  员工姓名:JAMES 部门名称:SALES
13  员工姓名:FORD 部门名称:RESEARCH
14  员工姓名:MILLER 部门名称:ACCOUNTING

另一种指定变量类型:

DECLARE
  V_EMPNAME EMP.ENAME%TYPE;
  V_DNAME   DEPT.DNAME%TYPE;
  CURSOR EMP_CUR IS
    SELECT E.ENAME, D.DNAME FROM EMP E, DEPT D WHERE E.DEPTNO = D.DEPTNO;
BEGIN
  OPEN EMP_CUR;
  LOOP
    FETCH EMP_CUR
      INTO V_EMPNAME, V_DNAME;
    EXIT WHEN EMP_CUR%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(员工姓名 : || V_EMPNAME || ,部门名称 : || V_DNAME);
  END LOOP;
  CLOSE EMP_CUR;
END;

结果同上

--定义游标例3:

DECLARE
  CURSOR CUR_EMP IS
    SELECT * FROM EMP;
  V_EMPROW EMP%ROWTYPE;
BEGIN
  IF CUR_EMP%ISOPEN THEN
    NULL;
  ELSE
    OPEN CUR_EMP;
  END IF;
  FETCH CUR_EMP
    INTO V_EMPROW;
  WHILE CUR_EMP%FOUND LOOP
    DBMS_OUTPUT.PUT_LINE(员工姓名:  || V_EMPROW.ENAME || ,职位:  ||
                         V_EMPROW.JOB ||  ,工资 || V_EMPROW.SAL);
    FETCH CUR_EMP
      INTO V_EMPROW;
  END LOOP;
  CLOSE CUR_EMP;
END;

结果:

员工姓名: SMITH,职位: CLERK ,工资800
员工姓名: ALLEN,职位: SALESMAN ,工资1600
员工姓名: WARD,职位: SALESMAN ,工资1250
员工姓名: JONES,职位: MANAGER ,工资2975
员工姓名: MARTIN,职位: SALESMAN ,工资1250
员工姓名: BLAKE,职位: MANAGER ,工资2850
员工姓名: CLARK,职位: MANAGER ,工资2450
员工姓名: SCOTT,职位: ANALYST ,工资3000
员工姓名: KING,职位: PRESIDENT ,工资5000
员工姓名: TURNER,职位: SALESMAN ,工资1500
员工姓名: ADAMS,职位: CLERK ,工资1100
员工姓名: JAMES,职位: CLERK ,工资950
员工姓名: FORD,职位: ANALYST ,工资3000
员工姓名: MILLER,职位: CLERK ,工资1300

--使用FOR循环

DECLARE 
CURSOR cur_emp IS SELECT * FROM emp;
BEGIN
  FOR emp_row IN cur_emp LOOP
    DBMS_OUTPUT.PUT_LINE(员工姓名:  || emp_row.ENAME || ,职位:  ||
                         emp_row.JOB ||  ,工资 || emp_row.SAL);
     END LOOP;
END;

结果同上

--使用FOR循环操作游标不仅代码简单,而且可以将游标的状态交给系统去完成,尽量使用FOR循环为主

--定义游标例4:使用游标UPDATE数据
--公司上市,决定给员工涨工资,入职年限超过1年加100,1000元封顶
--第一种 直接将计算的结果进行判断

DECLARE
  V_ID       EMP.EMPNO%TYPE;
  V_HIREDATE EMP.HIREDATE%TYPE;
  CURSOR EMP_CUR IS
    SELECT EMPNO, HIREDATE FROM EMP;
BEGIN
  OPEN EMP_CUR;
  LOOP
    FETCH EMP_CUR
      INTO V_ID, V_HIREDATE;
    EXIT WHEN EMP_CUR%NOTFOUND;
    IF (TO_CHAR(SYSDATE, yyyy) - TO_CHAR(V_HIREDATE, yyyy)) * 100 < 1000 THEN
      UPDATE EMP
         SET SAL = SAL +
                   (TO_CHAR(SYSDATE, yyyy) - TO_CHAR(V_HIREDATE, yyyy)) * 100
       WHERE EMPNO = V_ID;
      DBMS_OUTPUT.PUT_LINE(工资增加成功);
      COMMIT;
    ELSE
      UPDATE EMP SET SAL = SAL + 1000 WHERE EMPNO = V_ID;
      DBMS_OUTPUT.PUT_LINE(工资增加成功);
      COMMIT;
    END IF;
  END LOOP;
  CLOSE EMP_CUR;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE(数据异常);
    ROLLBACK;
END;

--第二种通过一个变量判断

DECLARE
  V_ID       EMP.EMPNO%TYPE; --定义员工编号ID
  V_HIREDATE EMP.HIREDATE%TYPE; --定义员工入职日期变量
  V_SAL      EMP.SAL%TYPE; --定义计算每个员工要涨工资的总数变量
  CURSOR CUR_EMP IS
    SELECT EMPNO, HIREDATE --定义游标查询员工ID和入职日期
      FROM EMP;
BEGIN
  IF CUR_EMP%ISOPEN THEN
    --判断游标是否打开
    NULL; --打开了就什么也不做
  ELSE
    OPEN CUR_EMP; --没有打开就打开游标
  END IF;
  LOOP
    FETCH CUR_EMP
      INTO V_ID, V_HIREDATE;
    EXIT WHEN CUR_EMP%NOTFOUND;
    V_SAL := (TO_CHAR(SYSDATE, yyyy) - TO_CHAR(V_HIREDATE, yyyy)) * 100;
    IF V_SAL < 1000 THEN
      --判断是否小于1000
      UPDATE EMP SET SAL = SAL + V_SAL WHERE EMPNO = V_ID;
      COMMIT;
    ELSE
      --大于1000
      UPDATE EMP SET SAL = SAL + 1000 WHERE EMPNO = V_ID;
      COMMIT;
    END IF;
  END LOOP;
  CLOSE CUR_EMP; --关闭游标
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE(数据异常);
    ROLLBACK; --出现异常 就回滚
END;

--定义游标例5
--在动态SELECT中使用游标

DECLARE
  V_LOWSAL EMP.SAL%TYPE := &LOWSAL;
  V_HISAL  EMP.SAL%TYPE := &HISSAL;
  CURSOR CUR_EMP IS
    SELECT * FROM EMP WHERE SAL BETWEEN V_LOWSAL AND V_HISAL;
BEGIN
  FOR EMP_ROW IN CUR_EMP LOOP
    DBMS_OUTPUT.PUT_LINE(员工姓名:  || EMP_ROW.ENAME || ,职位:  ||
                         EMP_ROW.JOB ||  ,工资 || EMP_ROW.SAL);
  END LOOP;
END;

--REF动态游标
TYPE 类型名 IS REF CURSOR [RETURN]数据类型
游标名 类型名
OPEN 游标名 FOR 查询语句
--强类型:带RETURN

DECLARE
  TYPE REF_EMP IS REF CURSOR RETURN EMP%ROWTYPE; --定义一个REF动态游标,并返回类型
  CUR_EMP REF_EMP; --定义一个变量类型是上面的REF动态游标也称游标变量
  V_EMP   EMP%ROWTYPE; --定义一个变量,类型和REF游标返回类型相同,行类型
BEGIN
  OPEN CUR_EMP FOR
    SELECT * FROM EMP; --打开游标,并关联查询语句
  LOOP
    FETCH CUR_EMP
      INTO V_EMP; --提取游标数据
    EXIT WHEN CUR_EMP%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(CUR_EMP%ROWCOUNT||  员工编号: || V_EMP.EMPNO ||  员工姓名: || V_EMP.ENAME);
  END LOOP;
  CLOSE CUR_EMP;
END;

--弱类型:不带RETURN

DECLARE
  TYPE REF_EMP IS REF CURSOR; --定义一个REF动态游标,并返回类型
  CUR_EMP REF_EMP; --定义一个变量类型是上面的REF动态游标也称游标变量
  V_EMP   EMP%ROWTYPE; --定义一个变量,类型和REF游标返回类型相同,行类型
  V_DEPT  DEPT%ROWTYPE; --定义一个变量,类型和REF游标返回类型相同,行类型
BEGIN
  --员工表
  OPEN CUR_EMP FOR
    SELECT * FROM EMP; --打开游标,并关联查询语句
  LOOP
    FETCH CUR_EMP
      INTO V_EMP; --提取游标数据
    EXIT WHEN CUR_EMP%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(CUR_EMP%ROWCOUNT ||   员工编号: || V_EMP.EMPNO ||
                          员工姓名: || V_EMP.ENAME);
  END LOOP;
  CLOSE CUR_EMP;
  ------------下面是部门表  
  OPEN CUR_EMP FOR
    SELECT * FROM DEPT; --打开游标,并关联查询语句
  LOOP
    FETCH CUR_EMP
      INTO V_DEPT; --提取游标数据
    EXIT WHEN CUR_EMP%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(CUR_EMP%ROWCOUNT ||   部门编号: || V_DEPT.DEPTNO ||
                          部门名称: || V_DEPT.DNAME);
  END LOOP;
  CLOSE CUR_EMP;
END;
在Oracle9i之后为了方便用户使用弱类型游标变量,可以使用  
SYS_REFCURSOR 来替代  TYPE REF_EMP IS REF CURSOR
上面的声明可以换为:
  CUR_EMP  SYS_REFCURSOR; --定义一个变量类型是上面的REF动态游标也称游标变量
  V_EMP   EMP%ROWTYPE; --定义一个变量,类型和REF游标返回类型相同,行类型
  V_DEPT  DEPT%ROWTYPE; --定义一个变量,类型和REF游标返回类型相同,行类型

--根据用户输入,来输出内容

DECLARE
  --TYPE REFC_T IS REF CURSOR;
  REFC    SYS_REFCURSOR;
  V_ID    NUMBER;
  V_NAME  VARCHAR2(50);
  V_INPUT VARCHAR(1) := UPPER(SUBSTR(&input, 1, 1));
BEGIN
  IF V_INPUT = E THEN
    OPEN REFC FOR
      SELECT EMPNO, ENAME FROM EMP;
    DBMS_OUTPUT.PUT_LINE(=====员工表信息======);
  ELSIF V_INPUT = D THEN
    OPEN REFC FOR
      SELECT DEPTNO, DNAME FROM DEPT;
    DBMS_OUTPUT.PUT_LINE(=====部门表信息======);
  ELSE
    DBMS_OUTPUT.PUT_LINE(=====员工表信息(E)或者部门表信息(D)=======);
    RETURN;
  END IF;
  FETCH REFC
    INTO V_ID, V_NAME;
  WHILE REFC%FOUND LOOP
    DBMS_OUTPUT.PUT_LINE(REFC%ROWCOUNT || #  || V_ID ||    || V_NAME);
    FETCH REFC
      INTO V_ID, V_NAME;
  END LOOP;
  CLOSE REFC;
END;

 

游标(学习笔记)

标签:

原文地址:http://www.cnblogs.com/liunanjava/p/4210594.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!