oracle ql/sql 相关语法解析
这篇文章主要介绍了Oracle中游标Cursor基本用法详解,还是比较全面的,具有一定参考价值,需要的朋友可以了解下。
?
查询 SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的 SELECT [DISTICT|ALL]{*|column[,column,...]} INTO (variable[,variable,...] |record) FROM {table|(sub-query)}[alias] WHERE............ PL/SQL中SELECT语句只返回一行数据。如果超过一行数据,那么就要使用显式游标(对游标的讨论我们将 %TYPE属性 在PL/SQL中可以将变量和常量声明为内建或用户定义的数据类型,以引用一个列名,同时继承他的数据类 例: v_empno SCOTT.EMP.EMPNO%TYPE; v_salary EMP.SALARY%TYPE; 不但列名可以使用%TYPE,而且变量、游标、记录,或声明的常量都可以使用%TYPE。这对于定义相同数据类 DELCARE V_A NUMBER(5):=10; V_B V_A%TYPE:=15; V_C V_A%TYPE; BEGIN DBMS_OUTPUT.PUT_LINE (‘V_A=‘||V_A||‘V_B=‘||V_B||‘V_C=‘||V_C); END SQL>/ V_A=10 V_B=15 V_C= PL/SQL procedure successfully completed. SQL> 其他DML语句 其它操作数据的DML语句是:INSERT、UPDATE、DELETE和LOCK TABLE,这些语句在PL/SQL中的语法与在SQL中 论过DML语句的使用这里就不再重复了。在DML语句中可以使用任何在DECLARE部分声明的变量,如果是嵌套 例: 1 CREATE OR REPLACE PROCEDURE FIRE_EMPLOYEE (pempno in number) 2 AS 3 v_ename EMP.ENAME%TYPE; 4 BEGIN 5 SELECT ename INTO v_ename 6 FROM emp 7 WHERE empno=p_empno; 8 INSERT INTO FORMER_EMP(EMPNO,ENAME) 9 VALUES (p_empno,v_ename); 10 DELETE FROM emp 11 WHERE empno=p_empno; 12 UPDATE former_emp 13 SET date_deleted=SYSDATE 14 WHERE empno=p_empno; 15 EXCEPTION 16 WHEN NO_DATA_FOUND THEN 17 DBMS_OUTPUT.PUT_LINE(‘Employee Number Not Found!‘); 18 END DML语句的结果 当执行一条DML语句后,DML语句的结果保存在四个游标属性中,这些属性用于控制程序流程或者了解程序 SQL%NOTFOUND,SQL%ROWCOUNT三个属性.SQL%FOUND,SQL%NOTFOUND是布尔值,SQL%ROWCOUNT是整数值。 SQL%FOUND和SQL%NOTFOUND 在执行任何DML语句前SQL%FOUND和SQL%NOTFOUND的值都是NULL,在执行DML语句后,SQL%FOUND的属性值将是: . TRUE :INSERT 当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE。 SQL%ROWCOUNT 在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于SELECT INTO语句,如果执行成功 SQL%ISOPEN SQL%ISOPEN是一个布尔值,如果游标打开,则为TRUE,如果游标关闭,则为FALSE.对于隐式游标而言SQL% 标在DML语句执行时打开,结束时就立即关闭。 事务控制语句 事务是一个工作的逻辑单元可以包括一个或多个DML语句,事物控制帮助用户保证数据的一致性。如果事务控制逻辑单元中的任何一个DML COMMIT语句终止事务,永久保存数据库的变化,同时释放所有LOCK,ROLLBACK终止现行事务释放所有LOCK, NT用于设置中间点,当事务调用过多的数据库操作时,中间点是非常有用的,SET TRANSACTION用于设置事 显式游标 查询返回结果超过一行时,就需要一个显式游标,此时用户不能使用select into语句。PL/SQL管理隐式 使用游标 这里要做一个声明,我们所说的游标通常是指显式游标,因此从现在起没有特别指明的情况,我们所说的 声明游标 语法: CURSOR cursor_name IS select_statement; 在PL/SQL中游标名是一个未声明变量,不能给游标名赋值或用于表达式中。 例: DELCARE CURSOR C_EMP IS SELECT empno,ename,salary FROM emp WHERE salary>2000 ORDER BY ename; ........ BEGIN ? 在游标定义中SELECT语句中不一定非要表可以是视图,也可以从多个表或视图中选择的列,甚至可以使用* 打开游标 使用游标中的值之前应该首先打开游标,打开游标初始化查询处理。打开游标的语法是: OPEN cursor_name cursor_name是在声明部分定义的游标名。 例: OPEN C_EMP; 关闭游标 语法: CLOSE cursor_name 例: CLOSE C_EMP; 从游标提取数据 从游标得到一行数据使用FETCH命令。每一次提取数据后,游标都指向结果集的下一行。语法如下: FETCH cursor_name INTO variable[,...] 对于SELECT定义的游标的每一列,FETCH变量列表都应该有一个变量与之相对应,变量的类型也要相同。 例: 1 SET SERVERIUTPUT ON 2 DECLARE 3 v_ename EMP.ENAME%TYPE; 4 v_salary EMP.SALARY%TYPE; 5 CURSOR c_emp IS SELECT ename,salary FROM emp; 6 BEGIN 7 OPEN c_emp; 8 FETCH c_emp INTO v_ename,v_salary; 9 DBMS_OUTPUT.PUT_LINE(‘Salary of Employee‘|| v_ename ||‘is‘|| v_salary); 10 FETCH c_emp INTO v_ename,v_salary; 11 DBMS_OUTPUT.PUT_LINE(‘Salary of Employee‘|| v_ename ||‘is‘|| v_salary); 12 FETCH c_emp INTO v_ename,v_salary; 13 DBMS_OUTPUT.PUT_LINE(‘Salary of Employee‘|| v_ename ||‘is‘|| v_salary); 14 CLOSE c_emp; 15 END 这段代码无疑是非常麻烦的,如果有多行返回结果,可以使用循环并用游标属性为结束循环的条件,以这 1 SET SERVERIUTPUT ON 2 DECLARE 3 v_ename EMP.ENAME%TYPE; 4 v_salary EMP.SALARY%TYPE; 5 CURSOR c_emp IS SELECT ename,salary FROM emp; 6 BEGIN 7 OPEN c_emp; 8 LOOP 9 FETCH c_emp INTO v_ename,v_salary; 10 EXIT WHEN c_emp%NOTFOUND; 11 DBMS_OUTPUT.PUT_LINE(‘Salary of Employee‘|| v_ename ||‘is‘|| v_salary); 12 END 记录变量 定义一个记录变量使用TYPE命令和%ROWTYPE,关于%ROWsTYPE的更多信息请参阅相关资料。 记录变量用于从游标中提取数据行,当游标选择很多列的时候,那么使用记录比为每列声明一个变量要方 当在表上使用%ROWTYPE并将从游标中取出的值放入记录中时,如果要选择表中所有列,那么在SELECT子句 例: 1 SET SERVERIUTPUT ON 2 DECLARE 3 R_emp EMP%ROWTYPE; 4 CURSOR c_emp IS SELECT * FROM emp; 5 BEGIN 6 OPEN c_emp; 7 LOOP 8 FETCH c_emp INTO r_emp; 9 EXIT WHEN c_emp%NOTFOUND; 10 DBMS_OUT.PUT.PUT_LINE(‘Salary of Employee‘||r_emp.ename||‘is‘|| r_emp.salary); 11 END LOOP; 12 CLOSE c_emp; 13 END; %ROWTYPE也可以用游标名来定义,这样的话就必须要首先声明游标: SET SERVERIUTPUT ON DECLARE CURSOR c_emp IS SELECT ename,salary FROM emp; R_emp c_emp%ROWTYPE; BEGIN OPEN c_emp; LOOP FETCH c_emp INTO r_emp; EXIT WHEN c_emp%NOTFOUND; DBMS_OUT.PUT.PUT_LINE(‘Salary of Employee‘||r_emp.ename||‘is‘|| r_emp.salary); END LOOP; CLOSE c_emp; END; 带参数的游标 与存储过程和函数相似,可以将参数传递给游标并在查询中使用。这对于处理在某种条件下打开游标的情 CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement; 定义参数的语法如下: Parameter_name [IN] data_type[{:=|DEFAULT} value] 与存储过程不同的是,游标只能接受传递的值,而不能返回值。参数只定义数据类型,没有大小。 另外可以给参数设定一个缺省值,当没有参数值传递给游标时,就使用缺省值。游标中定义的参数只是一个占位符,在别处引用该参数不一定可靠。 在打开游标时给参数赋值,语法如下: OPEN cursor_name[value[,value]....]; 参数值可以是文字或变量。 例: 1 DECALRE 2 CURSOR c_dept IS SELECT * FROM dept ORDER BY deptno; 3 CURSOR c_emp (p_dept VARACHAR2) IS 4 SELECT ename,salary 5 FROM emp 6 WHERE deptno=p_dept 7 ORDER BY ename 8 r_dept DEPT%ROWTYPE; 9 v_ename EMP.ENAME%TYPE; 10 v_salary EMP.SALARY%TYPE; 11 v_tot_salary EMP.SALARY%TYPE; 12 BEGIN 13 OPEN c_dept; 14 LOOP 15 FETCH c_dept INTO r_dept; 16 EXIT WHEN c_dept%NOTFOUND; 17 DBMS_OUTPUT.PUT_LINE(‘Department:‘|| r_dept.deptno||‘-‘||r_dept.dname); 18 v_tot_salary:=0; 19 OPEN c_emp(r_dept.deptno); 20 LOOP 21 FETCH c_emp INTO v_ename,v_salary; 22 EXIT WHEN c_emp%NOTFOUND; 23 DBMS_OUTPUT.PUT_LINE(‘Name:‘|| v_ename||‘ salary:‘||v_salary); 24 v_tot_salary:=v_tot_salary+v_salary; 25 END LOOP; 26 CLOSE c_emp; 27 DBMS_OUTPUT.PUT_LINE(‘Toltal Salary for dept:‘|| v_tot_salary); 28 END LOOP; 29 CLOSE c_dept; 30 END; 游标FOR循环 在大多数时候我们在设计程序的时候都遵循下面的步骤: 1、打开游标 可以简单的把这一类代码称为游标用于循环。但还有一种循环与这种类型不相同,这就是FOR循环,用于 游标FOR循环的语法如下: FOR record_name IN (corsor_name[(parameter[,parameter]...)] | (query_difinition) LOOP statements END LOOP; 下面我们用for循环重写上面的例子: 1 DECALRE 2 CURSOR c_dept IS SELECT deptno,dname FROM dept ORDER BY deptno; 3 CURSOR c_emp (p_dept VARACHAR2) IS 4 SELECT ename,salary 5 FROM emp 6 WHERE deptno=p_dept 7 ORDER BY ename 8 v_tot_salary EMP.SALARY%TYPE; 9 BEGIN 10 FOR r_dept IN c_dept LOOP 11 DBMS_OUTPUT.PUT_LINE(‘Department:‘|| r_dept.deptno||‘-‘||r_dept.dname); 12 v_tot_salary:=0; 13 FOR r_emp IN c_emp(r_dept.deptno) LOOP 14 DBMS_OUTPUT.PUT_LINE(‘Name:‘ || v_ename || ‘salary:‘ || v_salary); 15 v_tot_salary:=v_tot_salary+v_salary; 16 END LOOP; 17 DBMS_OUTPUT.PUT_LINE(‘Toltal Salary for dept:‘|| v_tot_salary); 18 END LOOP; 19 END; 在游标FOR循环中使用查询 在游标FOR循环中可以定义查询,由于没有显式声明所以游标没有名字,记录名通过游标查询来定义。 1 DECALRE 2 v_tot_salary EMP.SALARY%TYPE; 3 BEGIN 4 FOR r_dept IN (SELECT deptno,dname FROM dept ORDER BY deptno) LOOP 5 DBMS_OUTPUT.PUT_LINE(‘Department:‘|| r_dept.deptno||‘-‘||r_dept.dname); 6 v_tot_salary:=0; 7 FOR r_emp IN (SELECT ename,salary 8 FROM emp 9 WHERE deptno=p_dept 10 ORDER BY ename) LOOP 11 DBMS_OUTPUT.PUT_LINE(‘Name:‘|| v_ename||‘ salary:‘||v_salary); 12 v_tot_salary:=v_tot_salary+v_salary; 13 END LOOP; 14 DBMS_OUTPUT.PUT_LINE(‘Toltal Salary for dept:‘|| v_tot_salary); 15 END LOOP; 16 END; 游标中的子查询 语法如下: CURSOR C1 IS SELECT * FROM emp WHERE deptno NOT IN (SELECT deptno FROM dept WHERE dname!=‘ACCOUNTING‘); 可以看出与SQL中的子查询没有什么区别。 游标中的更新和删除 在PL/SQL中依然可以使用UPDATE和DELETE语句更新或删除数据行。显式游标只有在需要获得多行数据的情 语法: FOR UPDATE [OF [schema.]table.column[,[schema.]table.column].. 在多表查询中,使用OF子句来锁定特定的表,如果忽略了OF子句,那么所有表中选择的数据行都将被锁定。 在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如下: WHERE{CURRENT OF cursor_name|search_condition} 例: 1 DELCARE 2 CURSOR c1 IS SELECT empno,salary 3 FROM emp 4 WHERE comm IS NULL 5 FOR UPDATE OF comm; 6 v_comm NUMBER(10,2); 7 BEGIN 8 FOR r1 IN c1 LOOP 9 IF r1.salary<500 THEN 10 v_comm:=r1.salary*0.25; 11 ELSEIF r1.salary<1000 THEN 12 v_comm:=r1.salary*0.20; 13 ELSEIF r1.salary<3000 THEN 14 v_comm:=r1.salary*0.15; 15 ELSE 16 v_comm:=r1.salary*0.12; 17 END IF; 18 UPDATE emp; 19 SET comm=v_comm 20 WHERE CURRENT OF c1l; 21 END LOOP; 22 END -声明游标 --宗地表的调查日期LANDINFO_RESEARCHDATE --复制到流程表的权属调查时间FLOW_REASEARCHTIME 1 DECLARE 2 cursor cur_sel_all is select LANDINFO_RESEARCHDATE,LANDINFO_LANDNO from t_leoa_landinfo; --定义游标 3 l_date t_leoa_landinfo.landinfo_researchdate%type; --声明变量分别保存t_leoa_landinfo的各列 4 l_landNo t_leoa_landinfo.landinfo_landno%type; 5 begin 6 open cur_sel_all; 7 loop --循环取数,并将游标数据填充到返回纪录集合中 8 fetch cur_sel_all into l_date,l_landNo; 9 exit when cur_sel_all%NOTFOUND; --循环退出条件 10 if cur_sel_all%FOUND then --获取数据 11 update T_LEOA_BOOKFLOW t2 set FLOW_REASEARCHTIME = l_date where l_landNo = t2.landinfo_landno; 12 end if; 13 end loop; 14 close cur_sel_all; 15 end; 下面再分享一下另外一则游标使用方法的代码,具体如下: 1 -- 声明游标;CURSOR cursor_name IS select_statement 2 --For 循环游标 3 --(1)定义游标 4 --(2)定义游标变量 5 --(3)使用for循环来使用这个游标 6 declare 7 --类型定义 8 cursor c_job 9 is 10 select empno,job,sal 11 from emp 12 where job=‘MANAGER‘; 13 --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型 14 c_row c_job%rowtype; 15 begin 16 for c_row in c_job loop 17 dbms_output.put_line(c_row.empno||‘-‘||c_row.ename||‘-‘||c_row.job||‘-‘||c_row.sal); 18 end loop; 19 end; 20 --Fetch游标 21 --使用的时候必须要明确的打开和关闭 22 declare 23 --类型定义 24 cursor c_job 25 is 26 select empno,sal 27 from emp 28 where job=‘MANAGER‘; 29 --定义一个游标变量 30 c_row c_job%rowtype; 31 begin 32 open c_job; 33 loop 34 --提取一行数据到c_row 35 fetch c_job into c_row; 36 --判读是否提取到值,没取到值就退出 37 --取到值c_job%notfound 是false 38 --取不到值c_job%notfound 是true 39 exit when c_job%notfound; 40 dbms_output.put_line(c_row.empno||‘-‘||c_row.ename||‘-‘||c_row.job||‘-‘||c_row.sal); 41 end loop; 42 --关闭游标 43 close c_job; 44 end; ? 1 --1:任意执行一个update操作,用隐式游标sql的属性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。 2 begin 3 update emp set ENAME=‘ALEARK‘ WHERE EMPNO=7469; 4 if sql%isopen then 5 dbms_output.put_line(‘Openging‘); 6 else 7 dbms_output.put_line(‘closing‘); 8 end if; 9 if sql%found then 10 dbms_output.put_line(‘游标指向了有效行‘);--判断游标是否指向有效行 11 else 12 dbms_output.put_line(‘Sorry‘); 13 end if; 14 if sql%notfound then 15 dbms_output.put_line(‘Also Sorry‘); 16 else 17 dbms_output.put_line(‘Haha‘); 18 end if; 19 dbms_output.put_line(sql%rowcount); 20 exception 21 when no_data_found then 22 dbms_output.put_line(‘Sorry No data‘); 23 when too_many_rows then 24 dbms_output.put_line(‘Too Many rows‘); 25 end; 26 declare 27 empNumber emp.EMPNO%TYPE; 28 empName emp.ENAME%TYPE; 29 begin 30 if sql%isopen then 31 dbms_output.put_line(‘Cursor is opinging‘); 32 else 33 dbms_output.put_line(‘Cursor is Close‘); 34 end if; 35 if sql%notfound then 36 dbms_output.put_line(‘No Value‘); 37 else 38 dbms_output.put_line(empNumber); 39 end if; 40 dbms_output.put_line(sql%rowcount); 41 dbms_output.put_line(‘-------------‘); 42 select EMPNO,ENAME into empNumber,empName from emp where EMPNO=7499; 43 dbms_output.put_line(sql%rowcount); 44 if sql%isopen then 45 dbms_output.put_line(‘Cursor is opinging‘); 46 else 47 dbms_output.put_line(‘Cursor is Closing‘); 48 end if; 49 if sql%notfound then 50 dbms_output.put_line(‘No Value‘); 51 else 52 dbms_output.put_line(empNumber); 53 end if; 54 exception 55 when no_data_found then 56 dbms_output.put_line(‘No Value‘); 57 when too_many_rows then 58 dbms_output.put_line(‘too many rows‘); 59 end; ? --2,使用游标和loop循环来显示所有部门的名称 --游标声明 declare cursor csr_dept is --select语句 select DNAME from Depth; --指定行指针,这句话应该是指定和csr_dept行类型相同的变量 row_dept csr_dept%rowtype; begin --for循环 for row_dept in csr_dept loop dbms_output.put_line(‘部门名称:‘||row_dept.DNAME); end loop; end; ? 1 --3,使用游标和while循环来显示所有部门的的地理位置(用%found属性) 2 declare 3 --游标声明 4 cursor csr_TestWhile 5 is 6 --select语句 7 select LOC 8 from Depth; 9 --指定行指针 10 row_loc csr_TestWhile%rowtype; 11 begin 12 --打开游标 13 open csr_TestWhile; 14 --给第一行喂数据 15 fetch csr_TestWhile into row_loc; 16 --测试是否有数据,并执行循环 17 while csr_TestWhile%found loop 18 dbms_output.put_line(‘部门地点:‘||row_loc.LOC); 19 --给下一行喂数据 20 fetch csr_TestWhile into row_loc; 21 end loop; 22 close csr_TestWhile; 23 end; 24 select * from emp ? 1 --4,接收用户输入的部门编号,用for循环和游标,打印出此部门的所有雇员的所有信息(使用循环游标) 2 --CURSOR cursor_name[(parameter[,...)] IS select_statement; 3 --定义参数的语法如下:Parameter_name [IN] data_type[{:=|DEFAULT} value] 4 declare 5 CURSOR 6 c_dept(p_deptNo number) 7 is 8 select * from emp where emp.depno=p_deptNo; 9 r_emp emp%rowtype; 10 begin 11 for r_emp in c_dept(20) loop 12 dbms_output.put_line(‘员工号:‘||r_emp.EMPNO||‘员工名:‘||r_emp.ENAME||‘工资:‘||r_emp.SAL); 13 end loop; 14 end; 15 select * from emp 16 --5:向游标传递一个工种,显示此工种的所有雇员的所有信息(使用参数游标) 17 declare 18 cursor 19 c_job(p_job nvarchar2) 20 is 21 select * from emp where JOB=p_job; 22 r_job emp%rowtype; 23 begin 24 for r_job in c_job(‘CLERK‘) loop 25 dbms_output.put_line(‘员工号‘||r_job.EMPNO||‘ ‘||‘员工姓名‘||r_job.ENAME); 26 end loop; 27 end; 28 SELECT * FROM EMP 29 --6:用更新游标来为雇员加佣金:(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来 30 --http://zheng12tian.iteye.com/blog/815770 31 create table emp1 as select * from emp; 32 declare 33 cursor 34 csr_Update 35 is 36 select * from emp1 for update OF SAL; 37 empInfo csr_Update%rowtype; 38 saleInfo emp1.SAL%TYPE; 39 begin 40 FOR empInfo IN csr_Update LOOP 41 IF empInfo.SAL<1500 THEN 42 saleInfo:=empInfo.SAL*1.2; 43 elsif empInfo.SAL<2000 THEN 44 saleInfo:=empInfo.SAL*1.5; 45 elsif empInfo.SAL<3000 THEN 46 saleInfo:=empInfo.SAL*2; 47 END IF; 48 UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_Update; 49 END LOOP; 50 END; 51 --7:编写一个PL/SQL程序块,对名字以‘A‘或‘S‘开始的所有雇员按他们的基本薪水(sal)的10%给他们加薪(对emp1表进行修改操作) 52 declare 53 cursor 54 csr_AddSal 55 is 56 select * from emp1 where ENAME LIKE ‘A%‘ OR ENAME LIKE ‘S%‘ for update OF SAL; 57 r_AddSal csr_AddSal%rowtype; 58 saleInfo emp1.SAL%TYPE; 59 begin 60 for r_AddSal in csr_AddSal loop 61 dbms_output.put_line(r_AddSal.ENAME||‘原来的工资:‘||r_AddSal.SAL); 62 saleInfo:=r_AddSal.SAL*1.1; 63 UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_AddSal; 64 end loop; 65 end; 66 --8:编写一个PL/SQL程序块,对所有的salesman增加佣金(comm)500 67 declare 68 cursor 69 csr_AddComm(p_job nvarchar2) 70 is 71 select * from emp1 where JOB=p_job FOR UPDATE OF COMM; 72 r_AddComm emp1%rowtype; 73 commInfo emp1.comm%type; 74 begin 75 for r_AddComm in csr_AddComm(‘SALESMAN‘) LOOP 76 commInfo:=r_AddComm.COMM+500; 77 UPDATE EMP1 SET COMM=commInfo where CURRENT OF csr_AddComm; 78 END LOOP; 79 END; 80 --9:编写一个PL/SQL程序块,以提升2个资格最老的职员为MANAGER(工作时间越长,资格越老) 81 --(提示:可以定义一个变量作为计数器控制游标只提取两条数据;也可以在声明游标的时候把雇员中资格最老的两个人查出来放到游标中。) 82 declare 83 cursor crs_testComput 84 is 85 select * from emp1 order by HIREDATE asc; 86 --计数器 87 top_two number:=2; 88 r_testComput crs_testComput%rowtype; 89 begin 90 open crs_testComput; 91 FETCH crs_testComput INTO r_testComput; 92 while top_two>0 loop 93 dbms_output.put_line(‘员工姓名:‘||r_testComput.ENAME||‘ 工作时间:‘||r_testComput.HIREDATE); 94 --计速器减一 95 top_two:=top_two-1; 96 FETCH crs_testComput INTO r_testComput; 97 end loop; 98 close crs_testComput; 99 end; 100 --10:编写一个PL/SQL程序块,对所有雇员按他们的基本薪水(sal)的20%为他们加薪, 101 --如果增加的薪水大于300就取消加薪(对emp1表进行修改操作,并将更新前后的数据输出出来) 102 declare 103 cursor 104 crs_UpadateSal 105 is 106 select * from emp1 for update of SAL; 107 r_UpdateSal crs_UpadateSal%rowtype; 108 salAdd emp1.sal%type; 109 salInfo emp1.sal%type; 110 begin 111 for r_UpdateSal in crs_UpadateSal loop 112 salAdd:= r_UpdateSal.SAL*0.2; 113 if salAdd>300 then 114 salInfo:=r_UpdateSal.SAL; 115 dbms_output.put_line(r_UpdateSal.ENAME||‘: 加薪失败。‘||‘薪水维持在:‘||r_UpdateSal.SAL); 116 else 117 salInfo:=r_UpdateSal.SAL+salAdd; 118 dbms_output.put_line(r_UpdateSal.ENAME||‘: 加薪成功.‘||‘薪水变为:‘||salInfo); 119 end if; 120 update emp1 set SAL=salInfo where current of crs_UpadateSal; 121 end loop; 122 end; 123 --11:将每位员工工作了多少年零多少月零多少天输出出来 124 --近似 125 --CEIL(n)函数:取大于等于数值n的最小整数 126 --FLOOR(n)函数:取小于等于数值n的最大整数 127 --truc的用法 http://publish.it168.com/2005/1028/20051028034101.shtml 128 declare 129 cursor 130 crs_WorkDay 131 is 132 select ENAME,HIREDATE,trunc(months_between(sysdate,hiredate) / 12) AS SPANDYEARS,133 trunc(mod(months_between(sysdate,hiredate),12)) AS months,134 trunc(mod(mod(sysdate - hiredate,365),12)) as days 135 from emp1; 136 r_WorkDay crs_WorkDay%rowtype; 137 begin 138 for r_WorkDay in crs_WorkDay loop 139 dbms_output.put_line(r_WorkDay.ENAME||‘已经工作了‘||r_WorkDay.SPANDYEARS||‘年,零‘||r_WorkDay.months||‘月,零‘||r_WorkDay.days||‘天‘); 140 end loop; 141 end; 142 --12:输入部门编号,按照下列加薪比例执行(用CASE实现,创建一个emp1表,修改emp1表的数据),并将更新前后的数据输出出来 143 -- deptno raise(%) 144 -- 10 5% 145 -- 20 10% 146 -- 30 15% 147 -- 40 20% 148 -- 加薪比例以现有的sal为标准 149 --CASE expr WHEN comparison_expr THEN return_expr 150 --[,WHEN comparison_expr THEN return_expr]... [ELSE else_expr] END 151 declare 152 cursor 153 crs_caseTest 154 is 155 select * from emp1 for update of SAL; 156 r_caseTest crs_caseTest%rowtype; 157 salInfo emp1.sal%type; 158 begin 159 for r_caseTest in crs_caseTest loop 160 case 161 when r_caseTest.DEPNO=10 162 THEN salInfo:=r_caseTest.SAL*1.05; 163 when r_caseTest.DEPNO=20 164 THEN salInfo:=r_caseTest.SAL*1.1; 165 when r_caseTest.DEPNO=30 166 THEN salInfo:=r_caseTest.SAL*1.15; 167 when r_caseTest.DEPNO=40 168 THEN salInfo:=r_caseTest.SAL*1.2; 169 end case; 170 update emp1 set SAL=salInfo where current of crs_caseTest; 171 end loop; 172 end; 173 --13:对每位员工的薪水进行判断,如果该员工薪水高于其所在部门的平均薪水,则将其薪水减50元,输出更新前后的薪水,员工姓名,所在部门编号。 174 --AVG([distinct|all] expr) over (analytic_clause) 175 ---作用: 176 --按照analytic_clause中的规则求分组平均值。 177 --分析函数语法: 178 --FUNCTION_NAME(<argument>,<argument>...) 179 --OVER 180 --(<Partition-Clause><Order-by-Clause><Windowing Clause>) 181 --PARTITION子句 182 --按照表达式分区(就是分组),如果省略了分区子句,则全部的结果集被看作是一个单一的组 183 select * from emp1 184 DECLARE 185 CURSOR 186 crs_testAvg 187 IS 188 select EMPNO,ENAME,JOB,SAL,DEPNO,AVG(SAL) OVER (PARTITION BY DEPNO ) AS DEP_AVG 189 FROM EMP1 for update of SAL; 190 r_testAvg crs_testAvg%rowtype; 191 salInfo emp1.sal%type; 192 begin 193 for r_testAvg in crs_testAvg loop 194 if r_testAvg.SAL>r_testAvg.DEP_AVG then 195 salInfo:=r_testAvg.SAL-50; 196 end if; 197 update emp1 set SAL=salInfo where current of crs_testAvg; 198 end loop; 199 end; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |