• 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;
    年轻人能为世界年轻人能为世界做些什么
  • 相关阅读:
    ASP.NET 2.0 中的代码隐藏和编译
    魅族M8 UI新架构
    详细讲解大型数据库的设计原则与开发技巧
    [ZT]精彩的国外育儿教育读本,图文并茂
    企業導入ERP項目要防止「君子」作亂
    [ZT]VS2005 中 Lc.exe已退出,代码为 1,今天剛遇到就找了
    图像词汇
    VS2005 + VSS2005 的方法
    几种SQL Server数据库分页方式
    DB2 Express版与SQL Server标准版技术比较
  • 原文地址:https://www.cnblogs.com/twinkle-star/p/9398436.html
Copyright © 2020-2023  润新知