逆袭之旅DAY16.东软实训.Oracle.PL/SQL高级

  1  一、匿名块
  2  1、使用returning ... INTO 保存增删改表数据时的一些列的值
  301)增加数据时保存数据
  4 DECLARE
  5   v_ename emp.ename%TYPE;
  6   v_sal emp.sal%TYPE;
  7 BEGIN
  8   INSERT INTO emp(empno,ename,JOB,sal,comm,deptno) VALUES(&no,'zhaoliu','deve',3000,500,10) RETURNING ename,sal INTO v_ename,v_sal;
  9   dbms_output.put_line(v_ename || ','||v_sal);
 10 end;
 11 
 12 ---打开控制台输出开关
 13 SET serveroutput ON;
 14 
 15 (02)修改数据时保存数据
 16 DECLARE
 17   v_ename emp.ename%TYPE;
 18   v_sal emp.sal%type;
 19 BEGIN
 20   UPDATE emp SET sal=sal+100 WHERE empno=&no RETURNING ename,sal INTO v_ename,v_sal;
 21   dbms_output.put_line(v_ename || ','||v_sal);
 22 END;
 23 
 24 (03)删除数据时保存数据
 25 DECLARE
 26   v_ename emp.ename%TYPE;
 27   v_sal emp.sal%TYPE;
 28 BEGIN
 29   DELETE FROM emp WHERE empno=&no RETURNING ename,sal INTO v_ename,v_sal;
 30   dbms_output.put_line(v_ename || ','||v_sal);
 31 END;
 32 
 33 二、分支结构
 34 1if
 35 IF 条件 THEN 结果; 
 36 END IF;
 37 
 38 IF 条件 THEN 结果;
 39 ELSE 结果;
 40 END IF;
 41 
 42 IF 条件 THEN 结果;
 43 elsif 条件 THEN 结果;
 44 ....
 45 ELSE 结果;
 46 END IF;
 47 
 48 ---查询一个员工薪水,判断员工薪水如果大于3000,输出他是一个白领;如果工资小于等于3000大于1500,输出他是一个蓝领;其它情况输出是一个灰领;
 49 DECLARE
 50   v_sal emp.sal%TYPE;
 51 BEGIN
 52   SELECT sal INTO v_sal FROM emp WHERE empno=&no;
 53   IF v_sal>3000 THEN 
 54     dbms_output.put_line('白领');
 55   elsif v_sal>1500 THEN
 56     dbms_output.put_line('蓝领');
 57   ELSE dbms_output.put_line('灰领');
 58   END IF;
 59 END;
 60 
 61 2case:
 62 格式一:
 63   CASE WHEN 条件 THEN 结果;
 64        WHEN 条件 THEN 结果;
 65        ...
 66        ELSE 结果;
 67   END CASE;
 68 
 69 格式二:
 70   CASE 条件表达式 WHEN 值1 THEN 结果1;
 71                 WHEN 值2 THEN 结果2;
 72                 ....
 73                 ELSE 结果m;
 74   END CASE;
 75   
 76 ---输入一个成绩,判断该成绩等级,如果在99~90之间,返回为A,如果在89~80之间,返回为B,如果在79~70之间,返回C,其它返回为D
 77 DECLARE
 78   v_score NUMBER(3);
 79   v_flag VARCHAR2(1);
 80 BEGIN
 81   v_score:=&score;
 82   CASE trunc(v_score/10) WHEN 9 THEN v_flag:='A';
 83                          WHEN 8 THEN v_flag:='B';
 84                          WHEN 7 THEN v_flag:='C';
 85                          ELSE v_flag:='D';
 86   END CASE;
 87   dbms_output.put_line(v_score || ',该 成绩的等级为:' || v_flag);
 88 END;
 89 
 90 三、循环结构
 91 1、直到型循环
 92 loop
 93   执行循环体;
 94   exit WHEN 条件;
 95 END loop;
 96 
 97 ---在控制台输出1~5
 98 DECLARE
 99   v_i NUMBER(1):=1;
100 BEGIN
101   loop
102     dbms_output.put_line(v_i);
103     v_i:=v_i+1;
104     exit WHEN v_i>5;
105   END loop;
106 end;
107 
108 2while:
109 while 条件
110   loop
111     执行循环体;
112   END loop;
113   
114 ---在控制台输出1~5
115 DECLARE
116   v_i NUMBER(1):=1;
117 BEGIN
118   while v_i<=5
119     loop
120       dbms_output.put_line(v_i);
121       v_i:=v_i+1;
122     END loop;
123 end;
124 
125 3fOR:
126 FOR 循环变量 IN 最小值..最大值
127   loop
128     执行循环体;
129   END loop;
130 
131 ---在控制台输出1~5
132 BEGIN
133   for v_i in 1..5
134     loop
135       dbms_output.put_line(v_i);
136     END loop;
137 end;
138 
139 练习:
140 创建一张表,只包含一个字段id
141 先在表中插入一条记录5
142 然后将10—20之间的数插入两遍
143 
144 四、存储过程
145 语法:
146   CREATE [OR REPLACE] PROCEDURE 存储过程名(形参1 IN|out 数据类型,形参2 IN|out 数据类型...)
147   IS | AS
148     定义部分;
149   begin
150     执行部分;
151   exception
152     异常部分;
153   END;
154   
155 调用过程:
156   exec 存储过程名(实参...);
157   call 存储过程名(实参...);   ---如果调用的是无参存储过程,过程名后面必须()
158 
159 1、创建一个无参存储过程 
160 CREATE PROCEDURE pro_demo1
161 IS
162 BEGIN
163   INSERT INTO dept VALUES(50,'deve','nanjing');
164 end;
165   
166 exec pro_demo1;
167 call pro_demo1();
168 
169 2、创建一个输入参数存储过程
170 ---根据输入的员工工号和新的月薪修改数据库中该 员工的薪水
171 CREATE OR REPLACE PROCEDURE pro_demo1(NO emp.empno%TYPE,newsal emp.sal%TYPE)
172 is
173 BEGIN
174   update emp set sal=newsal where empno=no;
175 end;
176 
177 一个为雇员加薪的过程
178 CREATE OR REPLACE PROCEDURE pro_demo1(NO emp.empno%TYPE,addsal emp.sal%TYPE)
179 is
180 BEGIN
181   UPDATE emp SET sal=sal+addsal WHERE empno=NO;
182 end;
183 
184 
185 CALL pro_demo1(7788,10000);
186 
187 SELECT * FROM emp;
188 
189 3、创建一个即有输入参数也有输出参数存储过程
190 ---输出指定员工的姓名和工资
191 CREATE OR REPLACE PROCEDURE pro_demo2(NO emp.empno%TYPE,NAME out emp.ename%TYPE,salary out emp.sal%TYPE)
192 IS
193 BEGIN
194   SELECT ename,sal INTO NAME,salary FROM emp WHERE empno=NO;
195 END;
196 
197 
198 --使用匿名块调用存储过程
199 DECLARE
200   v_name VARCHAR2(30);
201   v_sal NUMBER(7);
202 BEGIN
203   pro_demo2(&no,v_name,v_sal);
204   dbms_output.put_line(v_name || ',' || v_sal);
205 end;
206   
207 五、函数
208 CREATE OR REPLACE FUNCTION 函数名(形参 数据类型,...) RETURN 数据类型
209 IS
210   定义部分;
211 BEGIN
212   执行部分;
213 exception
214   异常部分;
215 END;
216 
217 ---返回指定员工的年薪
218 CREATE OR REPLACE FUNCTION fun_demo1(NO emp.empno%TYPE) RETURN NUMBER
219 IS
220   v_salary NUMBER(10,2);
221 BEGIN
222   SELECT sal*12 INTO v_salary FROM emp WHERE empno=NO;
223   RETURN v_salary;
224 END;
225 
226 SELECT fun_demo1(7788) FROM dual;
227 
228 ---写一个函数,返回用户的姓名,入职日期,工资
229 CREATE OR REPLACE FUNCTION fun_demo2(NO emp.empno%TYPE) RETURN VARCHAR2
230 IS
231   v_ename emp.ename%TYPE;
232   v_hiredate varchar2(50);
233   v_sal emp.sal%TYPE;
234   v_info varchar2(200);
235 BEGIN
236   SELECT ename,to_char(hiredate,'yyyy-mm-dd'),sal INTO v_ename,v_hiredate,v_sal FROM emp WHERE empno=NO;
237   v_info:=v_ename ||','|| v_hiredate ||','|| v_sal;
238   RETURN v_info;
239 end;
240 
241 SELECT fun_demo2(7788) FROM dual;
242 
243 存储过程和函数的区别:
244 1.返回值的区别,函数返回值只有一个,而存储过程是通过输出参数来返回,可以有多个
245 2.调用的区别,函数可以在查询语句中直接调用,而存储过程必须单独调用
246 3.应用场合的区别,函数一般用来计算并返回计算的结果,而存储过程一般用来执行特定的操作,如创建表、创建用户等DDL语句
247 
248 五、包,里面包含的内容:存储过程,函数
249 语法:包括两个部分
250 声明部分:
251   CREATE OR REPLACE PACKAGE 包名
252   IS
253     声明内容;
254   END;
255 
256 包体的实体:
257   CREATE OR REPLACE PACKAGE BODY 包名
258   is
259     实现部分;
260   end;
261 
262 CREATE OR REPLACE PACKAGE pac_demo1
263 IS
264   PROCEDURE pro_demo1(NO emp.empno%TYPE,salary emp.sal%TYPE);
265   PROCEDURE pro_demo2(NO emp.empno%TYPE);
266   FUNCTION fun_demo1(NO emp.empno%TYPE) RETURN NUMBER;
267 end;
268 
269 create or replace package body pac_demo1
270 IS
271   PROCEDURE pro_demo1(NO emp.empno%TYPE,salary emp.sal%TYPE)
272   is
273   BEGIN
274     UPDATE emp SET sal=salary WHERE empno=NO;
275   END;
276   PROCEDURE pro_demo2(NO emp.empno%TYPE)
277   IS
278   BEGIN
279     DELETE FROM emp WHERE empno=NO;
280   END;
281   FUNCTION fun_demo1(NO emp.empno%TYPE) RETURN NUMBER
282   IS
283     v_salary number(10,2);
284   BEGIN
285     SELECT sal*12 INTO v_salary FROM emp WHERE empno=NO;
286     RETURN v_salary;
287   END;
288 end;
289 
290 CALL pac_demo1.pro_demo1(7788,20000);
291 SELECT * FROM emp;
292 CALL pac_demo1.pro_demo2(7788);
293 select pac_demo1.fun_demo1(7369) from dual;
294 
295 
296 
297 --1.创建一个包,包含一个为雇员加薪的过程,一个为雇员减薪的过程
298 CREATE OR REPLACE PACKAGE pac_test1
299 IS
300   PROCEDURE addsal(NO emp.empno%TYPE,addsal emp.sal%TYPE);
301   procedure minussal(no emp.empno%type,minussal emp.sal%type);
302 END;
303 
304 CREATE OR REPLACE PACKAGE body pac_test1
305 IS
306   PROCEDURE addsal(NO emp.empno%TYPE,addsal emp.sal%TYPE)
307   is
308   BEGIN
309     UPDATE emp SET sal=sal+addsal WHERE empno=NO;
310   end;
311   PROCEDURE minussal(NO emp.empno%TYPE,minussal emp.sal%TYPE)
312   IS
313   BEGIN
314     UPDATE emp SET sal=sal-minussal WHERE empno=NO;
315   end;
316 END;
317 
318 --2.编写一个过程,验证用户登陆。如果用户名、密码匹配,输出Y,否则输出N    emp表中的ename为用户名 empno为密码
319 CREATE OR REPLACE PROCEDURE pro_test2(username VARCHAR2,PASSWORD NUMBER,flag out VARCHAR2)
320 IS
321   v_count number(2);
322 BEGIN
323   SELECT count(empno) INTO v_count FROM emp WHERE ename=username AND empno=PASSWORD;
324   IF v_count>0 THEN flag:='Y';
325   ELSE flag:='N';
326   END IF;
327 END;
328 
329 --3.编写一个函数,根据雇员编号,计算调整后的工资
330 如果该雇员从事经理工作,且工资大于3000,则工资上涨20%,否则上涨35%
331 其他情况均上涨10%,输出雇员编号、姓名、上涨后的工资
332 
333 CREATE OR REPLACE FUNCTION fun_test3(NO emp.empno%TYPE) RETURN VARCHAR2
334 IS
335   v_ename emp.ename%TYPE;
336   v_sal emp.sal%TYPE;
337   v_newsal emp.sal%TYPE;
338   v_job emp.job%type;
339   v_info varchar2(100);
340 BEGIN
341   SELECT ename,sal,JOB INTO v_ename,v_sal,v_job FROM emp WHERE empno=NO;
342   IF upper(v_job)='MANAGER' THEN
343     IF v_sal>3000 THEN 
344       v_newsal:=v_sal*1.2;
345     ELSE v_newsal:=v_sal*1.35;
346     END IF;
347   ELSE v_newsal:=v_sal*1.1;
348   END IF;
349    v_info:= NO || ',' || v_ename || ',' || v_newsal;
350   RETURN v_info;
351 end;
352 
353 --4.创建一个包
354 包中含有一个存储过程,实现涨工资的功能,输入雇员姓名,如果其工作年限超过20年,工资增加2000
355 工作年限在10-20年,工资增加1000,工作年限在5-10年,工资增加500,输出雇员姓名和增涨后的工资
356 包中还含有一个函数,实现输入工资,判断工资如果大于4500,返回1,否则返回0
357 
358 CREATE OR REPLACE PACKAGE pac_test4
359 IS
360   PROCEDURE pro_addsal(NAME emp.ename%TYPE,info out VARCHAR2);
361   FUNCTION fun_sal(salary emp.sal%TYPE) RETURN NUMBER;
362 end;
363 
364 CREATE OR REPLACE PACKAGE body pac_test4
365 IS
366   PROCEDURE pro_addsal(NAME emp.ename%TYPE,info out VARCHAR2)
367   IS
368     v_year NUMBER(5);
369     v_sal emp.sal%TYPE;
370   BEGIN
371     SELECT trunc(months_between(SYSDATE,hiredate)/12),sal INTO v_year,v_sal FROM emp WHERE upper(ename)=upper(NAME);
372     IF v_year>20 THEN v_sal:=v_sal+2000;
373     elsif v_year>=10 THEN v_sal:=v_sal+1000;
374     elsif v_year>=5 THEN v_sal:=v_sal+500;
375     END IF;
376     info:=NAME || ','||v_sal;
377   end;
378   FUNCTION fun_sal(salary emp.sal%TYPE) RETURN NUMBER
379   IS
380     v_flag NUMBER(1);
381   BEGIN
382     IF salary>4500 THEN 
383       v_flag:=1;
384     ELSE v_flag:=0;
385     END IF;
386     RETURN v_flag;
387   end;
388 END;
389 
390 六、游标:
391 1、显示游标(查)、隐式游标(增删改)
392 使用显示游标有四个步骤:
39301):声明游标:cursor 游标名 IS 查询语句;
394   (02):打开游标:open 游标名;
395   (03):获取数据:fetch 游标名 INTO 变量名;
396   (04):关闭游标:close 游标名;
397   
398 游标属性:
399   %found:是否发现数据,如果发现,返回true,否则返回false
400   %notfound:是否没有数据,如果没有,返回true,否则返回false
401   %isopen:是否打开,如果打开,,返回true,否则返回false
402   %rowcount:返回涉及的行数
403   
404   
405 DECLARE
406   CURSOR cur IS SELECT * FROM dept;
407   v_dept dept%rowtype;
408 BEGIN
409   OPEN cur;
410   fetch cur INTO v_dept;
411   loop
412     dbms_output.put_line(v_dept.deptno || ','|| v_dept.dname || ','||v_dept.loc);
413     fetch cur INTO v_dept;
414   exit WHEN cur%notfound;
415   END loop;
416   CLOSE cur;
417 end;
418 
419 ---使用for循环读取游标指向的数据,打开游标、获取游标数据、关闭游标都自动
420 DECLARE
421   CURSOR cur IS SELECT * FROM dept;
422 BEGIN
423   FOR v_dept IN cur
424     loop
425       dbms_output.put_line(v_dept.deptno || ','|| v_dept.dname || ','||v_dept.loc);
426     END loop;
427 end;
428 
429 2、隐式游标:游标名为SQL,增删改
430 
431 ---修改指定员工的工资,如果员工不存在,提示员工不存在,如果存在,输出更新数据的行数
432 BEGIN
433   UPDATE emp SET sal=sal*1.2 WHERE empno=&no;
434   IF SQL%found THEN
435     dbms_output.put_line('更新数据的行数为:' || SQL%rowcount);
436   ELSE
437     dbms_output.put_line('对不起,该用户不存在');
438   END IF;
439 end;
440 
441 六、异常:
442 1、预定义异常:有异常号也有异常名
443 DECLARE
444   v_emp emp%rowtype;
445 BEGIN
446   SELECT * INTO v_emp FROM emp WHERE empno=&no;
447 exception
448   WHEN no_data_found THEN 
449     dbms_output.put_line('用户不存在');
450   WHEN too_many_rows THEN 
451     dbms_output.put_line('返回了多行数据');
452   WHEN others THEN 
453     dbms_output.put_line('程序出现了错误');
454 END;
455 
456 2、非预定义异常:有异常号没有异常名
457 3、自定义异常:没有异常号也没有异常名
458 
459 七、触发器
460 1、DML触发器:
461 
462 CREATE OR REPLACE TRIGGER 触发器名
463   AFTER|BEFORE INSERT|UPDATE|DELETE ON 表名
464   [FOR EACH ROW]  ---行触 发器
465 BEGIN
466   执行体;
467 end;
468 
469 ---如果有人删除emp表中的数据,给出警告信息
470 CREATE OR REPLACE trigger tri_demo1
471   AFTER DELETE ON emp
472 BEGIN
473   dbms_output.put_line('有人删除了emp表中的数据,请注意');
474 end;
475 
476 DELETE FROM emp WHERE empno=7566;
477 
478 CREATE OR REPLACE TRIGGER tri_demo1
479   AFTER DELETE or update or insert ON emp
480 BEGIN
481   IF deleting THEN
482     dbms_output.put_line('有人在删除emp表的数据');
483   elsif inserting THEN
484     dbms_output.put_line('有人新增了数据');
485   elsif updating THEN
486     dbms_output.put_line('有人修改了数据');
487   end if;
488 END;
489 
490         DELETE    INSERT    UPDATE
491 :NEW    无          有效      有效
492 :old    有效        无        有效
493 
494 CREATE OR REPLACE TRIGGER tri_demo3
495   before DELETE OR UPDATE OR INSERT ON emp
496   for each row
497 BEGIN
498   IF deleting THEN
499     dbms_output.put_line('有人在删除emp表的数据');
500     dbms_output.put_line(:old.ename ||','||:old.sal);
501   elsif inserting THEN
502     dbms_output.put_line('有人新增了数据');
503     dbms_output.put_line(:new.ename ||','||:new.sal);
504   elsif updating THEN
505     dbms_output.put_line('有人修改了数据');
506     dbms_output.put_line('原数据为:'||:OLD.ename ||','||:OLD.sal);
507     dbms_output.put_line('修改后的数据为:'||:new.ename ||','||:new.sal);
508   END IF;
509 END;
510 
511 
512 语句触发器:无论增加、删除、修改多少行数据,触发器只触发一次
513 行触发器:增加、删除、修改对于每一行涉及的数据,触发器都会执行
514 
515 INSERT INTO emp(empno,ename,sal) VALUES(1000,'bbb',6000);
516 commit;
517 
518 DELETE FROM emp WHERE deptno=10;
519 commit;

猜你喜欢

转载自www.cnblogs.com/twinkle-star/p/9398436.html
今日推荐