游标的概念:
游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块。在某些情况下,需要把数据从存放在磁 盘的表中调到计算机内存中进行处理,最后将处理结果显示出来或最终写回数据库。这样数据处理的速度才会提高,否则频繁的磁盘数据交换会降低效率。游标有两种类型:显式游标和隐式游标。在前述程序中用到的SELECT...INTO...查询语句,一次只能从数据库中提取一行数据,对于这种 形式的查询和DML操作,系统都会使用一个隐式游标。但是如果要提取多行数据,就要由程序员定义一个显式游标,并通过与游标有关的语句进行处理。显式游标 对应一个返回结果为多行多列的SELECT语句。 游标一旦打开,数据就从数据库中传送到游标变量中,然后应用程序再从游标变量中分解出需要的数据,并进行处理。隐式游标如前所述,DML操作和单行SELECT语句会使用隐式游标,它们是: * 插入操作:INSERT。 * 更新操作:UPDATE。 * 删除操作:DELETE。 * 单行查询操作:SELECT ... INTO ...。当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。隐式游标可以使用名字SQL来访问,但要注意, 通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。所以通常在刚刚执行完操作之后,立即使用SQL游标名来访问属性。游标 的属性有四种,如下所示。Sql代码
隐式游标的属性 返回值类型 意 义
SQL%ROWCOUNT 整型 代表DML语句成功执行的数据行数
SQL%FOUND 布尔型 值为TRUE代表插入、删除、更新或单行查询操作成功
SQL%NOTFOUND 布尔型 与SQL%FOUND属性返回值相反
SQL%ISOPEN 布尔型 DML执行过程中为真,结束后为假
Sql代码
SET SERVEROUTPUT ON
BEGIN
UPDATE emp SET sal=sal+100 WHERE empno=1234;
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('成功修改雇员工资!');
COMMIT;
ELSE
DBMS_OUTPUT.PUT_LINE('修改雇员工资失败!');
END IF;
END;
Sql代码
修改雇员工资失败!
PL/SQL 过程已成功完成。
Sql代码
成功修改雇员工资!
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
v_ename VARCHAR2(10);
v_job VARCHAR2(10);
CURSOR emp_cursor IS
SELECT ename,job FROM emp WHERE empno=7788;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO v_ename,v_job;
DBMS_OUTPUT.PUT_LINE(v_ename||','||v_job);
CLOSE emp_cursor;
END;
Sql代码
SCOTT,ANALYST
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
CURSOR emp_cursor IS SELECT ename,job,sal FROM emp WHERE empno=7788;
emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO emp_record;
DBMS_OUTPUT.PUT_LINE(emp_record.ename||','|| emp_record.job||','|| emp_record.sal);
CLOSE emp_cursor;
END;
Sql代码
SCOTT,ANALYST,3000
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
V_ename VARCHAR2(10);
V_sal NUMBER(5);
CURSOR emp_cursor IS SELECT ename,sal FROM emp ORDER BY sal DESC;
BEGIN
OPEN emp_cursor;
FOR I IN 1..3 LOOP
FETCH emp_cursor INTO v_ename,v_sal;
DBMS_OUTPUT.PUT_LINE(v_ename||','||v_sal);
END LOOP;
CLOSE emp_cursor;
END;
Sql代码
KING,5000
SCOTT,3000
FORD,3000
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
CURSOR emp_cursor IS
SELECT empno, ename FROM emp;
BEGIN
FOR Emp_record IN emp_cursor LOOP
DBMS_OUTPUT.PUT_LINE(Emp_record.empno|| Emp_record.ename);
END LOOP;
END;
Sql代码
7369SMITH
7499ALLEN
7521WARD
7566JONES
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
BEGIN
FOR re IN (SELECT ename FROM EMP) LOOP
DBMS_OUTPUT.PUT_LINE(re.ename)
END LOOP;
END;
Sql代码
SMITH
ALLEN
WARD
JONES
Sql代码
游标的属性 返回值类型 意 义
%ROWCOUNT 整型 获得FETCH语句返回的数据行数
%FOUND 布尔型 最近的FETCH语句返回一行数据则为真,否则为假
%NOTFOUND 布尔型 与%FOUND属性返回值相反
%ISOPEN 布尔型 游标已经打开时值为真,否则为假
Sql代码
SET SERVEROUTPUT ON
DECLARE
V_ename VARCHAR2(10);
CURSOR emp_cursor IS
SELECT ename FROM emp;
BEGIN
OPEN emp_cursor;
IF emp_cursor%ISOPEN THEN
LOOP
FETCH emp_cursor INTO v_ename;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(to_char(emp_cursor%ROWCOUNT)||'-'||v_ename);
END LOOP;
ELSE
DBMS_OUTPUT.PUT_LINE('用户信息:游标没有打开!');
END IF;
CLOSE emp_cursor;
END;
Sql代码
1-SMITH
2-ALLEN
3-WARD
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
V_empno NUMBER(5);
V_ename VARCHAR2(10);
CURSOR emp_cursor(p_deptno NUMBER, p_job VARCHAR2) IS
SELECT empno, ename FROM emp
WHERE deptno = p_deptno AND job = p_job;
BEGIN
OPEN emp_cursor(10, 'CLERK');
LOOP
FETCH emp_cursor INTO v_empno,v_ename;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno||','||v_ename);
END LOOP;
END;
Sql代码
7934,MILLER
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
v_empno NUMBER(5);
v_ename VARCHAR2(10);
v_deptno NUMBER(5);
v_job VARCHAR2(10);
CURSOR emp_cursor IS
SELECT empno, ename FROM emp
WHERE deptno = v_deptno AND job = v_job;
BEGIN
v_deptno:=10;
v_job:='CLERK';
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_empno,v_ename;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno||','||v_ename);
END LOOP;
END;
Sql代码
7934,MILLER
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
str varchar2(100);
v_ename varchar2(10);
begin
str:='select ename from scott.emp where empno=7788';
execute immediate str into v_ename;
dbms_output.put_line(v_ename);
END;
Sql代码
SCOTT
PL/SQL 过程已成功完成。
Sql代码
declare
type cur_type is ref cursor;
cur cur_type;
rec scott.emp%rowtype;
str varchar2(50);
letter char:= 'A';
begin
loop
str:= 'select ename from emp where ename like ''%'||letter||'%''';
open cur for str;
dbms_output.put_line('包含字母'||letter||'的名字:');
loop
fetch cur into rec.ename;
exit when cur%notfound;
dbms_output.put_line(rec.ename);
end loop;
exit when letter='Z';
letter:=chr(ascii(letter)+1);
end loop;
end;
Sql代码
包含字母A的名字:
ALLEN
WARD
MARTIN
BLAKE
CLARK
ADAMS
JAMES
包含字母B的名字:
BLAKE
包含字母C的名字:
CLARK
SCOTT
Sql代码
SET SERVEROUTPUT ON
DECLARE
v_name VARCHAR2(10);
BEGIN
SELECT ename
INTO v_name
FROM emp
WHERE empno = 1234;
DBMS_OUTPUT.PUT_LINE('该雇员名字为:'|| v_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('编号错误,没有找到相应雇员!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('发生其他错误!');
END;
Sql代码
编号错误,没有找到相应雇员!
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
v_temp NUMBER(5):=1;
BEGIN
v_temp:=v_temp/0;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('发生系统错误!');
DBMS_OUTPUT.PUT_LINE('错误代码:'|| SQLCODE( ));
DBMS_OUTPUT.PUT_LINE('错误信息:' ||SQLERRM( ));
END;
Sql代码
发生系统错误!
错误代码:?1476
错误信息:ORA-01476: 除数为 0
PL/SQL 过程已成功完成。
Sql代码
错 误 名 称 错误代码 错 误 含 义
CURSOR_ALREADY_OPEN ORA_06511 试图打开已经打开的游标
INVALID_CURSOR ORA_01001 试图使用没有打开的游标
DUP_VAL_ON_INDEX ORA_00001 保存重复值到惟一索引约束的列中
ZERO_DIVIDE ORA_01476 发生除数为零的除法错误
INVALID_NUMBER ORA_01722 试图对无效字符进行数值转换
ROWTYPE_MISMATCH ORA_06504 主变量和游标的类型不兼容
VALUE_ERROR ORA_06502 转换、截断或算术运算发生错误
TOO_MANY_ROWS ORA_01422 SELECT…INTO…语句返回多于一行的数据
NO_DATA_FOUND ORA_01403 SELECT…INTO…语句没有数据返回
TIMEOUT_ON_RESOURCE ORA_00051 等待资源时发生超时错误
TRANSACTION_BACKED_OUT ORA_00060 由于死锁,提交失败
STORAGE_ERROR ORA_06500 发生内存错误
PROGRAM_ERROR ORA_06501 发生PL/SQL内部错误
NOT_LOGGED_ON ORA_01012 试图操作未连接的数据库
LOGIN_DENIED ORA_01017 在连接时提供了无效用户名或口令
Sql代码
SET SERVEROUTPUT ON
DECLARE
V_ENAME VARCHAR2(10);
NULL_INSERT_ERROR EXCEPTION;
PRAGMA EXCEPTION_INIT(NULL_INSERT_ERROR,-1400);
BEGIN
INSERT INTO EMP(EMPNO) VALUES(NULL);
EXCEPTION
WHEN NULL_INSERT_ERROR THEN
DBMS_OUTPUT.PUT_LINE('无法插入NULL值!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('发生其他系统错误!');
END;
Sql代码
无法插入NULL值!
PL/SQL 过程已成功完成。
Java代码
SET SERVEROUTPUT ON
DECLARE
new_no NUMBER(10);
new_excp1 EXCEPTION;
new_excp2 EXCEPTION;
BEGIN
new_no:=6789;
INSERT INTO emp(empno,ename)
VALUES(new_no, '小郑');
IF new_no<7000 THEN
RAISE new_excp1;
END IF;
IF new_no>8000 THEN
RAISE new_excp2;
END IF;
COMMIT;
EXCEPTION
WHEN new_excp1 THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('雇员编号小于7000的下限!');
WHEN new_excp2 THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('雇员编号超过8000的上限!');
END;
Sql代码
SET SERVEROUTPUT ON
DECLARE
New_no NUMBER(10);
BEGIN
New_no:=6789;
INSERT INTO emp(empno,ename)
VALUES(new_no, 'JAMES');
IF new_no<7000 THEN
ROLLBACK;
RAISE_APPLICATION_ERROR(-20001, '编号小于7000的下限!');
END IF;
IF new_no>8000 THEN
ROLLBACK;
RAISE_APPLICATION_ERROR (-20002, '编号大于8000的下限!');
END IF;
END;
Sql代码
DECLARE
*
ERROR 位于第 1 行:
ORA-20001: 编号小于7000的下限!
ORA-06512: 在line 9
Sql代码
SET SERVEROUTPUT ON
DECLARE
v_empno NUMBER(5):=7788;
emp_rec emp%ROWTYPE;
BEGIN
SELECT * INTO emp_rec FROM emp WHERE empno=v_empno;
DELETE FROM emp WHERE empno=v_empno;
INSERT INTO emp1 VALUES emp_rec;
IF SQL%FOUND THEN
COMMIT;
DBMS_OUTPUT.PUT_LINE('雇员复制成功!');
ELSE
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('雇员复制失败!');
END IF;
END;
Sql代码
EMPNO ENAME JOB
------------- -------------- ----------------
7788 SCOTT ANALYST
Sql代码
SET SERVEROUTPUT ON
BEGIN
FOR re IN (SELECT ename,sal FROM EMP) LOOP
DBMS_OUTPUT.PUT_LINE(rpad(re.ename,12,' ')||rpad('*',re.sal/100,'*'));
END LOOP;
END;
Sql代码
SMITH ********
ALLEN ****************
WARD *************
JONES ******************************
MARTIN *************
BLAKE *****************************
CLARK *****************************
SCOTT ******************************
KING **************************************************
TURNER ***************
ADAMS ***********
JAMES **********
FORD ******************************
MILLER *************
执行结果为:
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
v_count number:=0;
CURSOR dept_cursor IS SELECT * FROM dept;
BEGIN
DBMS_OUTPUT.PUT_LINE('部门列表');
DBMS_OUTPUT.PUT_LINE('---------------------------------');
FOR Dept_record IN dept_cursor LOOP
DBMS_OUTPUT.PUT_LINE('部门编号:'|| Dept_record.deptno);
DBMS_OUTPUT.PUT_LINE('部门名称:'|| Dept_record.dname);
DBMS_OUTPUT.PUT_LINE('所在城市:'|| Dept_record.loc);
DBMS_OUTPUT.PUT_LINE('---------------------------------');
v_count:= v_count+1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('共有'||to_char(v_count)||'个部门!');
END;
Sql代码
部门列表
------------------------------------
部门编号:10
部门名称:ACCOUNTING
所在城市:NEW YORK
------------------------------------
部门编号:20
部门名称:RESEARCH
所在城市:DALLAS
...
共有4个部门!
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
v_deptno number(8);
v_count number(3);
v_sumsal number(6);
v_dname varchar2(15);
v_manager varchar2(15);
CURSOR list_cursor IS
SELECT deptno,count(*),sum(sal) FROM emp group by deptno;
BEGIN
OPEN list_cursor;
DBMS_OUTPUT.PUT_LINE('----------- 部 门 统 计 表 -----------');
DBMS_OUTPUT.PUT_LINE('部门名称 总人数 总工资 部门经理');
FETCH list_cursor INTO v_deptno,v_count,v_sumsal;
WHILE list_cursor%found LOOP
SELECT dname INTO v_dname FROM dept
WHERE deptno=v_deptno;
SELECT ename INTO v_manager FROM emp
WHERE deptno=v_deptno and job='MANAGER';
DBMS_OUTPUT.PUT_LINE(rpad(v_dname,13)||rpad(to_char(v_count),8)
||rpad(to_char(v_sumsal),9)||v_manager);
FETCH list_cursor INTO v_deptno,v_count,v_sumsal;
END LOOP;
DBMS_OUTPUT.PUT_LINE('--------------------------------------');
CLOSE list_cursor;
END;
Sql代码
-------------------- 部 门 统 计 表 -----------------
部门名称 总人数 总工资 部门经理
ACCOUNTING 3 8750 CLARK
RESEARCH 5 10875 JONES
SALES 6 9400 BLAKE
-------------------------------------------------------------
PL/SQL 过程已成功完成。
Sql代码
SET SERVEROUTPUT ON
DECLARE
V_NAME CHAR(10);
V_EMPNO NUMBER(5);
V_SAL NUMBER(8);
V_SAL1 NUMBER(8);
V_TOTAL NUMBER(8) := 800; --增加工资的总额
V_NUM NUMBER(5):=0; --增加工资的人数
CURSOR emp_cursor IS
SELECT EMPNO,ENAME,SAL FROM EMP ORDER BY SAL ASC;
BEGIN
OPEN emp_cursor;
DBMS_OUTPUT.PUT_LINE('姓名 原工资 新工资');
DBMS_OUTPUT.PUT_LINE('---------------------------');
LOOP
FETCH emp_cursor INTO V_EMPNO,V_NAME,V_SAL;
EXIT WHEN emp_cursor%NOTFOUND;
V_SAL1:= V_SAL*0.1;
IF V_TOTAL>V_SAL1 THEN
V_TOTAL := V_TOTAL - V_SAL1;
V_NUM:=V_NUM+1;
DBMS_OUTPUT.PUT_LINE(V_NAME||TO_CHAR(V_SAL,'99999')||
TO_CHAR(V_SAL+V_SAL1,'99999'));
UPDATE EMP SET SAL=SAL+V_SAL1
WHERE EMPNO=V_EMPNO;
ELSE
DBMS_OUTPUT.PUT_LINE(V_NAME||TO_CHAR(V_SAL,'99999')||TO_CHAR(V_SAL,'99999'));
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('---------------------------');
DBMS_OUTPUT.PUT_LINE('增加工资人数:'||V_NUM||' 剩余工资:'||V_TOTAL);
CLOSE emp_cursor;
COMMIT;
END;
Sql代码
姓名 原工资 新工资
---------------------------------------------
SMITH 1289 1418
JAMES 1531 1684
MARTIN 1664 1830
MILLER 1730 1903
ALLEN 1760 1936
ADAMS 1771 1771
TURNER 1815 1815
WARD 1830 1830
BLAKE 2850 2850
CLARK 2850 2850
JONES 2975 2975
FORD 3000 3000
KING 5000 5000
-----------------------------------------------
增加工资人数:5 剩余工资:3
PL/SQL 过程已成功完成。