一、游标语法概念和案例
1 一.课前回顾 2 存储过程的用途: 3 (1)它相当于方法,所以可以通过java代码调用存储过程, 4 使得存储过程的执行时机是可控的!(想什么时候执行都可以) 5 (2)存储过程中还可以调用游标! 6 (3)存储过程中可以执行赋值,sql的增删改查(查一条) 7 1.存储过程(有参数) 8 create or replace procedure p_名字 9 (v_变量名 in/out 数据类型) 10 is|as 11 定义变量 12 begin 13 执行内容 14 end; 15 16 2.存储过程(无参数) 17 create or replace procedure p_名字 18 is|as 19 定义变量 20 begin 21 执行内容 22 end; 23 24 3.单纯的调用存储过程 25 exec p_名字(实参|无参); 26 27 4.如果在plsql中调用存储过程, 28 p_名字(实参|无参); 29 30 5.异常 31 notfound → select ...into 的时候没有查到 32 others → 其他异常类型,必须放在异常列表的最后, 33 相当于java异常中的exception 34 35 二.游标 36 用途:查询批量数据,放入一个游标(集合) 37 2.1 使用步骤 38 (1)定义游标(相当于定义了一个集合) 39 cursor c_游标名 is 查询语句; 40 41 (2)打开游标 42 open c_游标名; 43 44 (3)提取游标内容 45 fetch c_游标名 into 变量1,变量2,...; 46 47 用循环去提取 48 while c_游标名%found loop 49 读取,打印,赋值 50 fetch c_游标名 into 变量1,变量2,...; 51 end loop; 52 53 loop循环 54 loop 55 fetch c_游标名 into 变量1,变量2,...; 56 读取,打印,赋值 57 exit when c_游标名%notfound; 58 end loop; 59 60 (4)关闭游标 61 close c_游标名; 62 63 (5)使用for 循环隐式打开游标,提取游标,关闭游标 64 (使用for循环不用显示的打开游标,提取游标,关闭游标) 65 --隐式的打开游标 66 for i in c_游标名 67 loop 68 --隐式的提取游标内容 69 读取,赋值,打印i.查询出的表字段 70 71 --隐式关闭游标 72 end loop; 73 74 (6)存储过程和游标结合的大概 75 create or replace procedure p_过程名(v_list out varchar2) 76 is|as 77 begin 78 v_list:=c_游标名; 79 end; 80 81 2.2 使用游标提取emp表中的所有数据 82 方法1:使用while循环提取游标内容 83 set serverout on 84 declare 85 --定义存储提取内容的变量 86 v_ename emp.ename%type; 87 v_sal emp.sal%type; 88 89 --定义游标 90 cursor c_emp is select ename,sal from emp; 91 begin 92 --打开游标 93 open c_emp; 94 95 --提取游标内容 96 fetch c_emp into v_ename,v_sal ; 97 98 --while循环打印游标读取的内容 99 while c_emp%found loop 100 dbms_output.put_line(c_emp%rowcount||‘--‘||v_ename||‘--‘||v_sal); 101 fetch c_emp into v_ename,v_sal ; 102 end loop; 103 104 --关闭游标 105 close c_emp; 106 end; 107 / 108 109 方法2:使用do-while循环提取游标内容 110 set serverout on 111 declare 112 --定义存储提取内容的变量 113 v_ename emp.ename%type; 114 v_sal emp.sal%type; 115 116 --定义游标 117 cursor c_emp is select ename,sal from emp; 118 begin 119 --打开游标 120 open c_emp; 121 122 --do-while循环打印游标读取的内容 123 loop 124 --提取游标内容 125 fetch c_emp into v_ename,v_sal ; 126 dbms_output.put_line(c_emp%rowcount||‘--‘||v_ename||‘--‘||v_sal); 127 exit when c_emp%notfound; 128 end loop; 129 130 --关闭游标 131 close c_emp; 132 end; 133 / 134 135 方法2:使用for循环提取游标内容 136 137 set serverout on 138 declare 139 cursor c_emp is select ename,sal from emp; 140 begin 141 for i in c_emp 142 loop 143 dbms_output.put_line(c_emp%rowcount||‘--‘||i.ename||‘--‘||i.sal); 144 end loop; 145 end; 146 / 147 148 2.3 查询所有的员工编号和工资,如果工资小于1200则在原来的基础上加50 149 150 --方法1:使用while循环 151 set serverout on 152 declare 153 --定义游标提取存放数据的变量 154 v_empno1 emp.empno%type; 155 v_sal1 emp.sal%type; 156 157 --定义游标 158 cursor c_emp is select empno,sal from emp; 159 begin 160 --打开游标 161 open c_emp; 162 163 --提取游标中的一行数据 164 fetch c_emp into v_empno1,v_sal1; 165 while c_emp%found 166 loop 167 dbms_output.put_line(v_empno1||‘--‘||v_sal1); 168 if v_sal1<=1200 then 169 update emp set sal=v_sal1+50 where empno=v_empno1; 170 dbms_output.put_line(v_empno1||‘修改成功‘); 171 select empno,sal into v_empno1,v_sal1 from emp 172 where empno=v_empno1; 173 dbms_output.put_line(v_empno1||‘--‘||v_sal1); 174 end if; 175 fetch c_emp into v_empno1,v_sal1; 176 end loop; 177 close c_emp; 178 end; 179 / 180 181 182 183 --方法2:使用do-while==loop循环 184 set serverout on 185 declare 186 --定义游标提取存放数据的变量 187 v_empno1 emp.empno%type; 188 v_sal1 emp.sal%type; 189 190 --定义游标 191 cursor c_emp is select empno,sal from emp; 192 begin 193 --打开游标 194 open c_emp; 195 196 fetch c_emp into v_empno1,v_sal1; 197 loop 198 199 dbms_output.put_line(v_empno1||‘--‘||v_sal1); 200 if v_sal1<=1200 then 201 update emp set sal=v_sal1+50 where empno=v_empno1; 202 dbms_output.put_line(v_empno1||‘修改成功‘); 203 select empno,sal into v_empno1,v_sal1 from emp 204 where empno=v_empno1; 205 dbms_output.put_line(v_empno1||‘--‘||v_sal1); 206 end if; 207 fetch c_emp into v_empno1,v_sal1; 208 exit when c_emp%notfound; 209 210 end loop; 211 close c_emp; 212 end; 213 / 214 215 --方法3:使用 for in循环 216 set serverout on 217 declare 218 v_empno emp.empno%type; 219 v_sal emp.sal%type; 220 cursor c_emp is select empno,sal from emp; 221 begin 222 for i in c_emp 223 loop 224 dbms_output.put_line(c_emp%rowcount||‘--‘||i.empno||‘--‘||i.sal); 225 if i.sal<=1200 then 226 update emp set sal=i.sal+50 where empno=i.empno; 227 select empno,sal into v_empno,v_sal from emp where empno=i.empno ; 228 229 dbms_output.put_line(i.empno||‘数据已经修改‘); 230 dbms_output.put_line(v_empno||‘--‘||v_sal); 231 end if; 232 end loop; 233 end; 234 / 235 236 2.4 定义有参数无返回值的游标 237 --题目:查询员工的编号和工资 238 set serverout on 239 declare 240 --定义有参数的游标 241 cursor c_emp(v_empno number) 242 is 243 select empno,sal from emp where empno=v_empno; 244 begin 245 dbms_output.put_line(‘编号--工资‘); 246 for i in c_emp(7369) 247 loop 248 dbms_output.put_line(i.empno||‘--‘||i.sal); 249 end loop; 250 end; 251 / 252 253 2.5 定义有参数有返回值类型的游标 254 --do-while循环 255 set serverout on 256 declare 257 --定义游标的返回值的列集 258 TYPE emp_record_type 259 is RECORD(v_empno emp.empno%type,v_sal emp.sal%type ); 260 261 --定义游标的返回值类型 262 v_emp_record_type EMP_RECORD_TYPE; 263 264 --定义有参数有返回值类型的游标 265 CURSOR c_emp(v_deptno emp.deptno%type) 266 RETURN EMP_RECORD_TYPE 267 IS 268 select empno,sal from emp where deptno=v_deptno; 269 270 begin 271 --打开游标 272 open c_emp(20); 273 dbms_output.put_line(‘编号--工资‘); 274 loop 275 --提取游标内容 276 fetch c_emp into v_emp_record_type; 277 dbms_output.put_line(v_emp_record_type.v_empno||‘--‘||v_emp_record_type.v_sal); 278 exit when c_emp%notfound; 279 end loop; 280 close c_emp; 281 end; 282 / 283 284 --for循环 285 set serverout on 286 declare 287 --定义游标的返回值的列集 288 TYPE emp_record_type 289 is RECORD(v_empno emp.empno%type,v_sal emp.sal%type ); 290 291 --定义游标的返回值类型 292 v_emp_record_type EMP_RECORD_TYPE; 293 294 --定义有参数有返回值类型的游标 295 CURSOR c_emp(v_deptno emp.deptno%type) 296 RETURN EMP_RECORD_TYPE 297 IS 298 select empno,sal from emp where deptno=v_deptno; 299 begin 300 dbms_output.put_line(‘编号--工资‘); 301 for i in c_emp(20) 302 loop 303 dbms_output.put_line(i.v_empno||‘--‘||i.v_sal); 304 end loop; 305 end; 306 /
游标语法概念和案例
二、显示游标、动态游标,动态sql
1 --1.显示游标的使用 2 --在dos窗口中写plsql块要输出内容必须写下面这句话 3 set serverout on 4 declare 5 --定义两个变量姓名和工资 6 name emp.ename%type; 7 sal emp.sal%type; 8 9 --定义游标 10 cursor cursor_emp is 11 select ename,sal from emp; 12 begin 13 14 --开启右边 15 open cursor_emp; 16 loop 17 --提取游标内容 18 fetch cursor_emp into name,sal; 19 exit when cursor_emp%notfound; 20 dbms_output.put_line(‘第‘||cursor_emp%rowcount||‘个雇员:‘||name||sal); 21 end loop; 22 23 --关闭游标 24 close cursor_emp; 25 end; 26 27 --dos窗口中写必须用次符号来结束 28 / 29 30 --输出结果: 31 第1个雇员:holly233.33 32 第2个雇员:管未433.33 33 34 --2.使用for in循环简化游标的读取自动结束 35 set serverout on 36 declare 37 --定义游标 38 cursor cursor_emp is 39 select ename,sal from emp; 40 begin 41 --for in循环游标,当游标中没有数据时自动停止并关闭游标 42 for i in cursor_emp 43 loop 44 dbms_output.put_line(‘第‘||cursor_emp%rowcount||‘个雇员:‘||i.ename||i.sal); 45 end loop; 46 end; 47 / 48 49 --3.动态有游标 50 set serverout on 51 declare 52 --定义弱类型游标数据类型 53 type cursor_type_scott is ref cursor; 54 55 --定义一个游标变量 56 cursor_scott cursor_type_scott; 57 58 --定义两个循增量 59 i emp%rowtype; 60 j dept%rowtype; 61 62 begin 63 --游标读取员工表 64 --打开游标并将内容放入游标变量 65 open cursor_scott for select * from emp where deptno=20; 66 loop 67 --提取游标变量里的内容 68 fetch cursor_scott into i; 69 70 --循环提取结束条件 71 exit when cursor_scott%notfound; 72 dbms_output.put_line(i.ename||‘的雇佣日期是‘||i.hiredate); 73 end loop; 74 75 --游标读取部门表 76 open cursor_scott for select * from dept where deptno in(10,20); 77 loop 78 fetch cursor_scott into j; 79 exit when cursor_scott%notfound; 80 dbms_output.put_line(j.deptno||‘表示‘||j.dname); 81 end loop; 82 83 --关闭游标 84 close cursor_scott; 85 end; 86 / 87 88 --输出结果为: 89 管未的雇佣日期是03-3月 -14 90 10表示ACCOUNTING 91 20表示RESEARCH 92 93 94 --4.动态sql创建表 95 --根据用户输入的表名及字段名等参数动态创建表t1 96 set serverout on 97 declare 98 table_name varchar2(20);--表名 99 field1 varchar2(20);--字段名 100 datatype1 varchar2(20);-- 字段类型 101 field2 varchar2(20);--字段名 102 datatype2 varchar2(20);-- 字段类型 103 str_sql varchar2(500); --存放sql语句的变量 104 105 begin 106 table_name:=‘t1‘; 107 field1:=‘id‘; 108 datatype1:=‘number‘; 109 field2:=‘name‘; 110 datatype2:=‘varchar2(20)‘; 111 str_sql:=‘create table ‘||table_name||‘(‘||field1||‘ ‘||datatype1||‘,‘||field2||‘ ‘||datatype2||‘)‘; 112 113 --动态创建表 114 execute immediate str_sql; 115 116 exception 117 when others then 118 dbms_output.put_line(‘操作失败!‘); 119 120 end; 121 / 122 123 运行结果: 124 PL/SQL 过程已成功完成。 125 desc t1; 126 名称 是否为空? 类型 127 ----------------------------------------- -------- ---------------------------- 128 ID NUMBER 129 NAME VARCHAR2(20) 130 131 132 --5.动态sql插入数据 133 set serverout on 134 declare 135 id number;--输入序号 136 name varchar2(20); --输入姓名 137 str_sql varchar2(500); --存储sql语句 138 begin 139 id:=1; 140 name:=‘Tom‘; 141 str_sql:=‘insert into t1 values(:1,:2)‘; 142 --动态插入数据 143 execute immediate str_sql using id,name; 144 exception 145 when others then 146 dbms_output.put_line(‘操作失败!‘); 147 end; 148 / 149 150 select * from t1; 151 152 运行结果: 153 PL/SQL 过程已成功完成。 154 select * from t1; 155 156 ID NAME 157 ------ ------------ 158 1 Tom 159 160 161 --6.动态sql查询总的数据条数 162 set serverout on 163 declare 164 v_id number:=1; 165 v_count number; 166 str_sql varchar2(500); 167 begin 168 str_sql:=‘select count(1) from t1 where id=:id‘; 169 --动态查询sql语句 170 execute immediate str_sql into v_count using v_id; 171 dbms_output.put_line(‘总的数据条数为:‘||v_count); 172 end; 173 / 174 175 --7.通过动态游标和动态sql一起使用查询多行数据 176 set serverout on 177 declare 178 type emp_cur is ref cursor; 179 my_emp_cur emp_cur; 180 my_emp_rec emp%rowtype; 181 182 begin 183 open my_emp_cur for ‘select * from emp where deptno=:x‘ using 30; 184 loop 185 fetch my_emp_cur into my_emp_rec; 186 exit when my_emp_cur%notfound; 187 dbms_output.put_line(my_emp_rec.ename||‘→‘||my_emp_rec.sal); 188 end loop; 189 end; 190 / 191 192 运行结果: 193 ALLEN→1600 194 WARD→1250 195 MARTIN→1250 196 BLAKE→2850 197 TURNER→1500 198 JAMES→950 199 200 PL/SQL 过程已成功完成。 201 202 203 --8.使用动态sql的DBMS_SQL包根据用户输入的表名、字段名及字段类型见表 204 set serverout on 205 declare 206 table_name2 varchar2(20); 207 field1 varchar2(20); 208 datatype1 varchar2(20); 209 field2 varchar2(20); 210 datatype2 varchar2(20); 211 v_cursor number; 212 v_string varchar2(200); 213 v_row number; 214 215 begin 216 table_name2:=‘t2‘; 217 field1:=‘id‘; 218 datatype1:=‘number‘; 219 field2:=‘name‘; 220 datatype2:=‘varchar2(20)‘; 221 v_cursor:=dbms_sql.open_cursor; 222 v_string:=‘create table ‘||table_name2||‘(‘||field1||‘ ‘||datatype1||‘,‘||field2||‘ ‘||datatype2||‘)‘; 223 dbms_sql.parse(v_cursor,v_string,dbms_sql.native); 224 v_row:=dbms_sql.execute(v_cursor); 225 dbms_sql.close_cursor(v_cursor); 226 dbms_output.put_line(v_row); 227 exception 228 when others then 229 dbms_sql.close_cursor(v_cursor); 230 raise; 231 end; 232 / 233 234 desc t2; 235 名称 是否为空? 类型 236 ----------------------------------------- -------- ------------- 237 ID NUMBER 238 NAME VARCHAR2(20) 239 240 241 --9.使用动态sql的DBMS_SQL包将表中t1中id=1的名称改为marry 242 set serverout on 243 declare 244 id number; 245 name varchar2(20); 246 v_cursor number; 247 v_string varchar2(200); 248 v_row number; 249 250 begin 251 id:=1; 252 name:=‘Marry‘; 253 v_cursor:=dbms_sql.open_cursor; 254 v_string:=‘update t1 set name=:p_name where id=:p_id‘; 255 dbms_sql.parse(v_cursor,v_string,dbms_sql.native); 256 dbms_sql.bind_variable(v_cursor,‘:p_name‘,name); 257 dbms_sql.bind_variable(v_cursor,‘:p_id‘,id); 258 v_row:=dbms_sql.execute(v_cursor); 259 dbms_sql.close_cursor(v_cursor); 260 exception 261 when others then 262 dbms_sql.close_cursor(v_cursor); 263 raise; 264 end; 265 / 266 267 PL/SQL 过程已成功完成。 268 select * from t1; 269 270 271 ID NAME 272 ---------- ---------------- 273 1 Marry
显示游标、动态游标,动态sql
三、隐式游标
1 一.隐式游标 2 调用游标时:SQL% 3 4 1.1 删除某个部门下的员工信息,如果该部门下没有员工,则删除部门表中的该部门信息 5 6 set serverout on 7 declare 8 --动态输入删除的条件 9 v_deptno emp.deptno%type:=&p_deptno; 10 --定义接受受影响行数的变量 11 v_count number; 12 begin 13 delete from emp where deptno=v_deptno; 14 --接受受影响的行数赋值给变量 15 v_count:=SQL%rowcount; 16 17 --判断受影响的行数是否>0,如果为true就删除员工,否则删除部门信息 18 if v_count>0 then 19 dbms_output.put_line(‘部门编号为:‘||v_deptno||‘的员工信息已经被删除‘); 20 else 21 delete from dept where deptno=v_deptno; 22 if SQL%ROWCOUNT>0 then 23 dbms_output.put_line(‘部门编号为:‘||v_deptno||‘的部门信息已经被删除‘); 24 else 25 dbms_output.put_line(‘部门编号为:‘||v_deptno||‘数据没有找到‘); 26 end if; 27 end if; 28 end; 29 / 30 31 1.2 动态游标 32 --1.2.1 使用动态的弱类型游标实现查询员工信息和部门信息 33 set serverout on 34 declare 35 --<1>定义弱类型游标 36 TYPE TYPE_CURSOR_SCOTT IS REF CURSOR; 37 38 --<2>定义游标变量 39 c_scott TYPE_CURSOR_SCOTT; 40 41 --<3>定义存储两个表数据的变量,相当于list 42 e emp%rowtype; 43 d dept%rowtype; 44 45 --<4>定义一个查询条件的变量 46 v_deptno emp.deptno%type:=&p_deptno; 47 48 begin 49 --游标读取员工信息表 50 --打开游标并将内容放入游标变量 51 open c_scott 52 for 53 select * from emp where deptno=v_deptno; 54 dbms_output.put_line(‘员工编号--员工工资‘); 55 loop 56 fetch c_scott into e; 57 exit when c_scott%notfound; 58 dbms_output.put_line(e.empno||‘--‘||e.sal); 59 end loop; 60 61 --打开游标并将内容放入游标变量 62 open c_scott 63 for 64 select * from dept; 65 dbms_output.put_line(‘部门编号--部门名字‘); 66 --循环读取游标内容 67 loop 68 fetch c_scott into d; 69 exit when c_scott%notfound; 70 dbms_output.put_line(d.deptno||‘--‘||d.dname); 71 end loop; 72 73 --关闭游标 74 close c_scott; 75 end; 76 / 77 78 79 输入 p_deptno 的值: 10 80 原值 13: v_deptno emp.deptno%type:=&p_deptno; 81 新值 13: v_deptno emp.deptno%type:=10; 82 7782--2450 83 7839--5000 84 7934--1300 85 128--ccc 86 143--新部门11 87 144--啊啊啊 88 10--统计1部 89 20--RESEARCH 90 30--销售7部 91 40--OPERATIONS 92 41--测试部 93 42--产品研发部 94 49--d1 95 104--商业3部 96 97 1.3 使用动态sql创建表 98 set serverout on 99 declare 100 --①.定义表名 101 table_name varchar2(20); 102 --②定义id列 103 id_name varchar2(20); 104 105 --③定义id列的数据类型 106 idtype varchar2(20); 107 108 --④定义name列 109 name varchar2(20); 110 111 --⑤定义name列的数据类型 112 nametype varchar2(20); 113 114 --⑥定义存放sql语句的变量 115 strsql varchar2(500); 116 begin 117 table_name:=‘t1‘; 118 id_name:=‘id‘; 119 idtype:=‘number‘; 120 name:=‘name‘; 121 nametype:=‘varchar2(20)‘; 122 123 strsql:=‘create table ‘||table_name 124 ||‘(‘||id_name||‘ ‘||idtype||‘,‘||name||‘ ‘|nametype||‘)‘; 125 dbms_output.put_line(‘sql语句:‘||strsql); 126 127 --执行动态sql语句 128 execute immediate strsql; 129 exception 130 when others then 131 dbms_output.put_line(‘创建表失败!‘); 132 end; 133 / 134 135 --1.4.动态sql插入数据 136 set serverout on 137 declare 138 id number;--输入序号 139 name varchar2(20); --输入姓名 140 str_sql varchar2(500); --存储sql语句 141 begin 142 id:=1; 143 name:=‘Tom‘; 144 str_sql:=‘insert into t1 values(:1,:2)‘; 145 --动态插入数据 146 execute immediate str_sql using id,name; 147 exception 148 when others then 149 dbms_output.put_line(‘操作失败!‘); 150 end; 151 / 152 153 select * from t1; 154 155 --1.5.动态sql查询总的数据条数(没有条件的) 156 set serverout on 157 declare 158 v_count number; 159 str_sql varchar2(500); 160 begin 161 str_sql:=‘select count(1) from t1‘; 162 --动态查询sql语句 163 execute immediate str_sql into v_count; 164 dbms_output.put_line(‘总的数据条数为:‘||v_count); 165 end; 166 / 167 168 --1.6.动态sql查询总的数据条数(有条件的) 169 set serverout on 170 declare 171 v_id number; 172 v_count number; 173 str_sql varchar2(500); 174 begin 175 v_id:=1; 176 str_sql:=‘select count(1) from t1 where id=:id‘; 177 --动态查询sql语句 178 execute immediate str_sql into v_count using v_id; 179 dbms_output.put_line(‘总的数据条数为:‘||v_count); 180 end; 181 / 182 183 --1.7 动态sql和动态游标结合查询多行数据 184 set serverout on 185 declare 186 --定义游标类型 187 TYPE c_type_emp IS REF CURSOR; 188 189 --定义游标类型变量 190 c_emp c_type_emp; 191 192 --定义存储where条件的变量 193 v_deptno emp.deptno%type:=&p_deptno; 194 195 --定义行数据类类型(表=集合) 196 list emp%rowtype; 197 198 begin 199 --打开游标,同时使用动态sql,给占位符赋值 200 open c_emp 201 for ‘select * from emp where deptno=:deptno‘ 202 using v_deptno; 203 204 --循环提取游标内容 205 loop 206 --先提取一行数据 207 fetch c_emp into list; 208 exit when c_emp%notfound ; 209 210 dbms_output.put_line(list.ename||‘-‘||list.deptno); 211 end loop; 212 213 --关闭游标 214 close c_emp; 215 end; 216 / 217 218 输入 p_deptno 的值: 30 219 原值 9: v_deptno emp.deptno%type:=&p_deptno; 220 新值 9: v_deptno emp.deptno%type:=30; 221 ALLEN-30 222 WARD-30 223 MARTIN-30 224 BLAKE-30 225 TURNER-30 226 JAMES-30 227
隐式游标
时间: 2024-10-11 06:41:49