--8. 选择部门为30中的所有员工 select * from new_scott; select * from new_scott where deptno = 30 ; --9. 列出所有办事员(CLERK)的姓名,编号和部门编号 selectdistinct ename from new_scott where job='CLERK';
--10. 找出佣金高于薪金的员工。 select * from new_scott where comm>sal;
--11. 找出佣金高于薪金60%的员工 select * from new_scott where comm>(sal*0.6);
--12. 找出部门10中所有的(MANAGER)和部门20中所有办事员(CLERK)。 select * from new_scott where (deptno=10and job = 'MANAGER') or (deptno = 20and job = 'CLERK'); --插入信息 INSERTinto new_scott values(7347,'Bob','CLERK',7876,to_date('1999-02-15','yyyy-mm-dd'),1000,0,10); -- select * from new_scott where empno = '7347'; COMMIT;--提交 ROLLBACK;--回滚
--修改当前回话的日期格式 --alter session set sysdate_formate = 'YYYY-MM-DD HH24:MI:SS';
--更新 update new_scott set ename = 'james'where empno = 7347;
--删除 delete new_scott where empno = 7347;
--DCL ||||| commit:提交 rollback:回滚 savepoint :表即可回滚的点 delete new_scott where ename = 'JONES'; savepoint mark1; update new_scott set ename = 'chengui' where empno = 7369; savepoint mark2; rollbacktosavepoint mark1; --链接符|| select empno||'姓名'||ename||'工作'||job||'上司'||mgr||'入职时间'||hiredate||'工资'||sal||'佣金'||comm||'部门编号'||deptno from new_scott; --like 匹配 select * from new_scott where job like'_A%'; select * from new_scott where ename like'\%' ; select ename , sal,nvl(comm,0),sal+nvl(comm,0) salary from new_scott; select * from new_scott where mgr isnotnull; --13. 找出收取佣金的员工的不同工作 selectdistinct job from new_scott where comm isnotnull; --14. 找出不收取佣金或收取的佣金不低于100的员工 select * from new_scott where comm isnullor comm<100 orderby empno
--15. 找出部门10中所有的(MANAGER)和部门20中所有办事员(CLERK), --和既不是经理又不是办事员但其薪金大于或等于2000的所有员工的详细资料 select * from new_scott where (deptno = 10and job = 'MANAGER'or deptno = 20AND JOB = 'CLERK' ) OR (JOB NOTIN ('MANAGER','CLERK') AND SAL>=2000);
--16. 找出各月倒数第三天受雇的所有员工 select * from new_scott whereextract(DAYfromlast_day(hiredate))- extract(DAYfrom (hiredate))=2;
select * from new_scott
--17. 找出早于25年前受雇佣的员工 select * from new_scott whereextract(yearfrom systimestamp)- extract(yearfrom (hiredate))>25;
--18. 以首字母大写其它字母小写的方式显示所有的员工的姓名。 select empno,INITCAP(LOWER(ename)),job,mgr,hiredate,sal,comm,deptno from new_scott;
createtable salgrade as select * from scott.salgrade;
select e.* from new_scott n, salgrade s where e.sal between s.lowsal and s.hisal;
select'工号为:'|| e.empno||'的员工的名字是'||e.ename||'的上司是'||temp.empno ||temp.ename from new_scott e join new_scott temp on e.mgr = temp.empno;
--工资分类 select e.* ,f.* from new_scott e join salgrade f on e.sal >f.losal and e.sal< f.hisal;
createtrigger tri_salgrade_insert afterinsert on salgrade begin RAISE_APPLICATION_ERROR ('YOU MAY ERRROR'); end;
INSERTinto salgrade values(6,4000,9999)
--查询在‘NEW YORK’工作,工资高于2000的员工以及员工的工资等级。 --方法一: select n.*,s.grade ,dept.* from new_scott n , salgrade s,newdept dept where n.deptno = dept.deptno and n.sal>s.losal and n.sal<s.hisal and n.sal>2000and dept.loc = 'NEW YORK' --方法二: select n.*,s.grade,dept.* from new_scott n join salgrade s on n.sal>s.losal and n.sal<s.hisal join newdept dept on dept.deptno = n.deptno and n.sal>2000and dept.loc like'NEW YORK';
select n.empno,n.ename,sal,loc from new_scott n, (select * from newdept where newdept.loc = 'NEW YORK'and deptno = 10 ) S where n.deptno = s.deptno;
select * from newdept; select * from NEW_SCOTT; select * from newdept;
--31. 查询部门名称为SALES和ACCOUNTING的员工信息 /* 1 7499 ALLEN SALESMAN 7698 1981/2/20 1600.00 300.00 30 30 SALES CHICAGO 2 7521 WARD SALESMAN 7698 1981/2/22 1250.00 500.00 30 30 SALES CHICAGO 3 7654 MARTIN SALESMAN 7698 1981/9/28 1250.00 1400.00 30 30 SALES CHICAGO 4 7698 BLAKE MANAGER 7839 1981/5/1 2850.00 30 30 SALES CHICAGO 5 7782 CLARK MANAGER 7839 1981/6/9 2450.00 10 10 ACCOUNTING NEW YORK 6 7839 KING PRESIDENT 1981/11/17 5000.00 10 10 ACCOUNTING NEW YORK 7 7844 TURNER SALESMAN 7698 1981/9/8 1500.00 0.00 30 30 SALES CHICAGO 8 7900 JAMES CLERK 7698 1981/12/3 950.00 30 30 SALES CHICAGO 9 7934 MILLER CLERK 7782 1982/1/23 1300.00 10 10 ACCOUNTING NEW YORK */ select * from new_scott e,newdept n where e.deptno = n.deptno and n.dname in ('SALES','ACCOUNTING'); --32. 查询不是经理的员工的信息(使用in 或 not in来做) /* 1 7369 SMITH CLERK 7902 1980/12/17 800.00 20 2 7499 ALLEN SALESMAN 7698 1981/2/20 1600.00 300.00 30 3 7521 WARD SALESMAN 7698 1981/2/22 1250.00 500.00 30 4 7654 MARTIN SALESMAN 7698 1981/9/28 1250.00 1400.00 30 5 7844 TURNER SALESMAN 7698 1981/9/8 1500.00 0.00 30 6 7876 ADAMS CLERK 7788 1987/5/23 1100.00 20 7 7900 JAMES CLERK 7698 1981/12/3 950.00 30 8 7934 MILLER CLERK 7782 1982/1/23 1300.00 10 */ select * from new_scott where empno notin (selectdistinct mgr from new_scott where mgr isnotnull);
--33. 查询工资比10号部门员工中任意一个低的员工信息(13) select * from new_scott e where e.sal < any (selectdistinct sal from new_scott where deptno = 10)
--34. 查询工资比10号部门都要低的员工信息 select * from new_scott e where e.sal <all (selectdistinct sal from new_scott where deptno = 10)
--35. 查询出部门名称,部门员工数,部门平均工资,部门最低工资雇员的姓名,及工资等级 select n.dname,t.deptno,t.total,t.ag,t.mi,s.grade,e.ename from new_scott e ,salgrade s,newdept n,(select deptno, count(*) total, avg(sal) ag, min(sal) mi from new_scott groupby deptno) t where e.deptno = t.deptno and e.sal>=s.losal and e.sal<=s.hisal and n.deptno = e.deptno and e.sal in (select mi from (select deptno, count(*) total, avg(sal) ag, min(sal) mi from new_scott groupby deptno) t) --36. 列出最低薪金大于1500的各种工作及此从事此工作的全部雇员人数 /* 1 ANALYST 2 2 MANAGER 3 3 PRESIDENT 1 */ --方法一 selectdistinct(e.job),t.total from new_scott e,(select job ,min(sal) mi,count(*) total from new_scott groupby job)t where e.job = t.job and t.mi > 1500; --方法二 select e.job, count(*)人数 from emp e groupby e.job having (selectmin(sal) from emp where e.em)
--37. 求出在'salesman'部门工作的员工姓名,假设不知道销售部的部门编号 selectdistinct e.ename from new_scott e,newdept n where e.deptno = (selectdistinct deptno from new_scott where job = UPPER('salesman'));
--38. 列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,公司的工资等级
select e.ename,e.sal,n.dname,e.mgr,s.grade from new_scott e,newdept n,salgrade s where e.sal >(selectavg(sal) from new_scott ) and e.deptno = n.deptno and e.sal >s.losal and e.sal <=s.hisal;
--39. 列出于“SCOTT”从事相同工作的所有员工及部门名称
select e.ename ,n.dname from new_scott e,newdept n where e.job = (select job from new_scott where ename = 'SCOTT') and e.deptno = n.deptno;
--40. 查询和SMITH部门相同 岗位相同的人 select * from new_scott e, newdept n where e.deptno = (select deptno from new_scott where ename = 'SMITH' ) and e.job = (select job from new_scott where ename = 'SMITH') and e.deptno = n.deptno;
--41. 和ALLEN同部门,工资高于MARTIN的雇员有哪些 select * from new_scott e where e.deptno = (select deptno from new_scott where ename = 'ALLEN') and e.sal > (select sal from new_scott where ename = 'ALLEN')
--42. 比blake工资高的雇员有哪些? select * from new_scott e where e.sal > (select sal from new_scott where ename = upper('blake'))
--43. 高于30部门最高工资的雇员有哪些? select * from new_scott e where e.sal > (selectmax(sal) from new_scott where deptno = 30)
--44. 查询scott用户下的emp表中所有的经理的信息(此操作子查询会返回多行记录) select * from new_scott where empno in (select mgr from new_scott);
--45. 工资高于本部门平均工资的人(拿上游工资的人)有哪些?**** select e.* from new_scott e where e.sal >(selectavg(sal) from new_scott where deptno = e.deptno)
select e.deptno ,e.empno,e.sal,e.ename from new_scott e,(select deptno,avg(sal) ag from new_scott groupby deptno ) t where t.deptno = e.deptno and e.sal > t.ag groupby e.deptno ,e.empno,e.ename,e.sal;
--46. 工作和部门与SMITH相同,工资高于JAMES的雇员有哪些? select * from new_scott e,newdept n where e.job = (select job from new_scott where ename = 'SMITH') and e.deptno = n.deptno and n.deptno = (select new_scott.deptno from new_scott,newdept where ename = 'SMITH'and new_scott.deptno = newdept.deptno ) and e.sal >(select sal from new_scott where ename = 'JAMES');
--删除没有员工的部门 --方法一 delete newdept where deptno in (select deptno from newdept MINUSselectdistinct deptno from new_scott)and deptno <> 40; --方法二 delete newdept where deptno notin (select deptno from new_scott)
--创建同义词: -- 1)创建私有同义词 注意:需要sys授权:grant create SYNONYM to stu;
createorreplacepublicsynonym emp for new_scott ;
-- 2)创建共有同义词 注意:需要sys授权:grant create public SYNONYM to stu; createpublicsynonym dept1 for newdept; --drop public synonym dept;
--创建视图 createview emp_view as select * from emp; select * from emp_view; --删除视图 dropview emp_view;
select empno,ename,dname from emp e,newdept d where e.deptno = d.deptno AND e.ename<>'SCOTT'AND e.job=(select job from emp where ename='SCOTT'); --创建索引 createindex emp_job on emp(job); --验证索引 select * from emp where job = upper('salesman');
--第一个小例子 BEGIN dbms_output.put_line('最简单的PL/SQL'); END;
declare v_money number(4,1) := 2.3; begin dbms_output.put_line(v_money); end;
--第二个小例子 DECLARE v_ename VARCHAR2(20); --运行时在输入 v_ename2 v_ename%type; --引用另一个变量的类型 v_empno NUMBER(4) not null := 7999; --初始化 v_empno2 NUMBER(4); --运行时在输入 v_job emp.job%type; --变量与job列的数据类型和宽度一致 v_hiredate emp.hiredate%type default sysdate; --赋默认值 v_sal CONSTANT emp.sal%type := 3000; --常量 BEGIN --赋值方式 1: v_ename := '&请输入员工姓名:'; --&号表示一个替代变量,可在运行时输入值,字符串需用单引号括起来 v_empno2 := &请输入员工编号; --赋值方式 2: select 列名列表 into 变量列表(对号入座) --但是要注意现在给变量赋值不能返回多行,要处理多行的查询结果需要用到游标 SELECT job INTO v_job FROM emp WHERE empno=v_empno2; --8001
--更新方式(emp 为 new_scott 的同义词 synonym) declare v_empno emp.empno%TYPE; v_ename emp.ename%TYPE; v_sal emp.sal %TYPE; begin v_empno:=&员工工号; select ename,sal into v_ename,v_sal from emp where emp.empno = v_empno; dbms_output.put_line(v_empno||' 的名字是:'||v_ename||' 薪水是:'||v_sal); if v_sal < 3000 then update emp set sal = sal +500where empno = v_empno; dbms_output.put_line(v_ename||'加薪完成!'); else dbms_output.put_line('薪水已经很高了!'); endif; end;
--IF-ELSE案例 --create or replace procedure emp_add_sal --is -- begin declare v_empno emp.empno% rec_emp emp%rowtype; begin v_empno := &员工编号; --更新前 select * into rec_emp from emp where empno = v_empno; dbms_output.put_line('更新前:员工编号:'||rec_emp.empno||', 员工名字:'||rec_emp.ename||', 员工工资:'||rec_emp.sal); if(rec_emp.sal<3000) then update emp set sal = sal-500where empno = v_empno; else update emp set sal = sal-200where empno = v_empno; endif; -- commit; --更新后 select * into rec_emp from emp where empno = v_empno; dbms_output.put_line('更新后:员工编号:'||rec_emp.empno||', 员工名字:'||rec_emp.ename||', 员工工资:'||rec_emp.sal); --处理没有找到数据的异常 exception when NO_DATA_FOUND THEN dbms_output.put_line('查无此人!'); when others then dbms_output.put_line('错误代码:'||SQLCODE ||',错误信息:'||SQLERRM); end; --end emp_add_sal; /
--第一种方式 declare v_score integerdefault0; begin v_score:= &成绩; case when v_score >=80 then dbms_output.put_line('优秀'); when v_score >=70and v_score<80 then dbms_output.put_line('良好'); when v_score >=60 and v_score <70 then dbms_output.put_line('一般'); else dbms_output.put_line('不及格'); endcase; end;
--第二种方式 declare v_grade char(2); begin case'&grade'-- 此处一定注意:如果是字符型一定要加上 '' 否者报错,,,如果是数值型则不需要加 ’‘ when'A'then dbms_output.put_line('优秀'); when 'B' then dbms_output.put_line('良好'); when 'C' then dbms_output.put_line('一般'); else dbms_output.put_line('不及格'); endcase; end;
--循环 declare v_row int:= &行数; v_counter1 int :=1; v_counter2 int :=1; begin loop v_counter1 := 1; loop dbms_output.put('*'); exit when v_counter1=v_counter2; v_counter1:=v_counter1+1; endloop; dbms_output.new_line; v_counter2:=v_counter2+1; exit when v_counter2 = v_row; endloop;
end;
--使用LOOP循环求1-100之间的素数 declare v_prime int :=2; v_counter int default 1; counter int default 0; num int default 0;--统计个数 begin loop counter:=0;--计数器(每次重新开始) v_counter:=2;--除数 从 2~v_prime 除(每次重新开始) loop if v_prime mod v_counter = 0 then counter:=counter+1; endif; exit when v_counter = v_prime or counter > 2; --内循环结束条件 (2个条件满足一个即可跳出循环) v_counter:=v_counter+1;--除数自加 endloop; if counter = 1 then--输出语句 num:= num+1; if num<>1 then dbms_output.put(','); endif; dbms_output.put(v_prime); endif; exit when v_prime=100;--外循环结束条件 v_prime:= v_prime+1;--外循环自加 endloop; dbms_output.new_line; end;
--九九乘法表 declare counter1 intdefault1; counter2 int default 1; begin counter1 :=&乘法表范围; for i in 1..9 loop for j in 1..i loop dbms_output.put(i||'*'||j||'='||i*j); if(j<>i)then dbms_output.put(','); endif; endloop; dbms_output.new_line; endloop; end; --52.使用FOR循环求1-100之间的素数 declare counter int :=0; begin for i in2..100loop counter:=0; for j in 2..i loop if mod(i,j)=0 then counter:=counter+1; endif; exit when counter >1; endloop; if counter = 1 then dbms_output.put(i||','); endif; endloop; dbms_output.new_line; end;
/* 练习: 根据部门名称,按以下格式打印"RESEARCH"部门所有人员姓名: 部门名称:RESEARCH 部门人员:SMITH,JONES,FORD */ declare counter int ; v_ename emp.ename%type; begin dbms_output.put_line('部门名称:'||'RESEARCH'); dbms_output.put('部门人员:'); selectcount(*) into counter from emp e,newdept n --统计有多少个符合条件的 where e.deptno = n.deptno and n.dname = 'RESEARCH'; for i in 1..counter loop --由于每次只能打印一个,所以用for循环 select ename into v_ename from ( selectrownum r,ename --用伪列rownum 为每一个符合的条件做个编号,以便输出 from emp e join newdept n on e.deptno = n.deptno and n.dname = 'RESEARCH' )a where a.r = i; dbms_output.put(v_ename); if i<>counter then dbms_output.put(','); endif; endloop; dbms_output.new_line(); end;
declare v_sal emp.sal%type; v_ename emp.ename%type; begin v_sal := &请输入工资; select ename into v_ename from emp where sal = v_sal; dbms_output.put_line('工资为:'||v_sal||'的员工姓名是:'||v_ename); exception when NO_DATA_FOUND then dbms_output.put_line('查无此人!'); end;
---自定义异常 declare v_empno emp.empno%type:=&加薪员工的工号; v_count int default 0; v_sal emp.sal%type; invlite_sal exception;--自定义异常 no_found exception; --自定义异常 begin v_sal:=&工资; if v_sal<0 then raise invlite_sal; -- 手动抛出异常 endif; selectcount(*) into v_count from emp where empno = v_empno; if(v_count = 0) then raise no_found ; --手动抛出异常 endif; exception --捕获异常 when no_found then dbms_output.put_line('没有符合的信息!'); when invlite_sal then dbms_output.put_line('工资不可为负!'); end;
--记录类型 declare type rec_emp_type isrecord( empno emp.empno%type, ename emp.ename%type, sal emp.sal%type ); no_found exception; rec rec_emp_type ; v_count int:=0; v_empno emp.empno%type:=&请输入员工工号; begin selectcount(*)into v_count from emp where empno = v_empno; if v_count = 0 then raise no_found; endif; select empno,ename,sal into rec from emp where empno = v_empno; dbms_output.put_line('员工工号:'||rec.empno ||'员工姓名:'||rec.ename ||'员工薪水:'||rec.sal); exception when no_found then -- raise_application_error(-20010,'查无此人'); dbms_output.put_line('查无此人'); end; -------------------------------------------第六章 游标--------------------------------------------------- ----游标(loop访问) declare cursor cv_emp is--1.定义游标 cursor 游标名 is (select 语句) select e.* ,rownumfrom emp e; rec_emp cv_emp%rowtype; --定义一个游标类型的变量,保存每次结果 begin open cv_emp; --2.打开游标 open 游标名; loop fetch cv_emp into rec_emp; -- 3.从游标中获取数据 : fetch 有标明 into 变量 dbms_output.put_line(rec_emp.empno||' '||rec_emp.rownum); exit when cv_emp%NOTFOUND; endloop; close cv_emp; --4.关闭游标 close 游标名 end; --while访问 declare cursor cv_emp is select e.*,rownumfrom emp e ;--order by empno rec_emp cv_emp%rowtype; begin open cv_emp; fetch cv_emp into rec_emp; --因为游标是从0开始,第零个没有数据,所以要跳过, while cv_emp%FOUND LOOP dbms_output.put_line(rec_emp.empno||' '||REC_EMP.ROWNUM); fetch cv_emp into rec_emp; ENDLOOP; close cv_emp; end; --for declare cursor cv_emp is select e.*,rownumfrom emp e ;--order by empno begin for rec_emp in cv_emp loop--for 不需要特意定义 游标变量,因为 ORACLE 自动分配计数器变量 dbms_output.put_line(rec_emp.empno||' '||rec_emp.rownum); endloop ; end; --for 升级版 begin for rec_emp in (select e.*,rownumfrom emp e ) loop--直接用select 语句作为 匿名的 cursor dbms_output.put_line(rec_emp.empno||' '||rec_emp.rownum); endloop ; end; /* ---------------------------------------------第六章 游标管理 作业----------------------------------*/
/* (一)什么是游标: (二)隐式游标:在 PL/SQL 程序中执行DML SQL 语句时自动创建隐式游标。 并且只能访问最近执行的一条DML语句,查询只能返回一行。 (三)显式游标用于处理返回多行的查询。 1)无参数的显式游标 2)带参数的显式游标 语法: cursor 游标名(参数名 类型) is select_statement; (四)隐式游标的特性: 1)在PL/SQL中使用DML语句时自动创建隐式游标 2)隐式游标自动声明、自动打开和自动关闭,其名为: SQL 3)通过检查隐式游标的属性可以获得最近一次执行的DML 语句的信息 4)游标的属性有: (1)%FOUND – SQL语句查询或影响了一行或多行时为 TRUE (2)%NOTFOUND – SQL语句没有影响任何行时为 TRUE (3)%ROWCOUNT – SQL语句影响的行数 (4)%ISOPEN - 检查游标是否打开,隐式游标始终为FALSE (五)使用游标更新行 1) 查询时使用 select .. from table where 条件 for update [of column [nowait]]子句锁定需要更新的行或列。 2) update employee set sal=sal-2 where current of 游标; */
--54. 显示EMP中的第四条记录。 如:游标%rowcount=4 declare cursor cv_emp isselect * from emp; rec_emp cv_emp%rowtype; begin open cv_emp; loop fetch cv_emp into rec_emp; --先移动,再读取 if cv_emp%rowcount = 4 then dbms_output.put_line(rec_emp.empno||' '||rec_emp.ename); endif; exit when cv_emp%rowcount = 4; endloop; close cv_emp; end;
--方法一:不带参数游标 declare begin for rec_emp in (select dname,deptno from newdept d) loop dbms_output.put_line('部门名称:'||rec_emp.dname); dbms_output.put('部门人员:'); for rec_tep in (select e.ename ename ,e.deptno deptno from emp e join newdept n on e.deptno = n.deptno ) loop if rec_tep.deptno = rec_emp.deptno then dbms_output.put(rec_tep.ename||','); endif; endloop; dbms_output.new_line; endloop; end; --方式二:带参数游标 declare cursor cv_dept is select * from newdept ; cursor cv_employee (cp_deptno emp.deptno%type)--传递一个员工部门参数,根据参数锁定该部门信息 is select * from emp where deptno = cp_deptno; begin for cp_dept in cv_dept loop dbms_output.put_line('部门名称:'||cp_dept.dname); dbms_output.put('部门员工:'); for cp_emp in cv_employee(cp_dept.deptno) loop --内循环中的参数是外循环给的,通过每一个部门参数,打印结果 dbms_output.put(cp_emp.ename||','); endloop; dbms_output.new_line; dbms_output.new_line; --空一行 endloop; end;
/* 56. 对所有员工,如果该员工职位是MANAGER,并且在DALLAS工作那么就给他薪金加15%;如果该员工职位是CLERK,并且在NEW YORK工作那么就给他薪金扣除5%;其他情况不作处理 */ --方式二: 游标 declare cursor cv_emp(p_job emp.job%type,p_loc newdept.loc%type)is select e.sal,e.deptno,n.loc from emp e,newdept n where e.deptno = n.deptno and p_job = e.job and p_loc = n.loc forupdate; v_job emp.job%type; v_loc newdept.loc%type; begin v_job:='&工作:'; v_loc:='&地点:'; for rec_emp in cv_emp(v_job,v_loc) loop if v_job='MANAGER' and v_loc = 'DALLAS' then update emp set sal= sal*(1+0.15) wherecurrentof cv_emp; endif; if v_job='CLERK' and v_loc = 'NEW YORK' then update emp set sal= sal*(1-0.05) wherecurrentof cv_emp; endif; endloop; end;
--方式一: declare cursor cv_emp isselect empno ,e.job job, n.loc loc from emp e join newdept n on e.deptno = n.deptno forupdate; begin FOR rec_emp in cv_emp loop if rec_emp.job ='MANAGER'and rec_emp.loc ='DALLAS'then update emp set sal= sal*(1+0.15) where empno = rec_emp.empno; --where current of cv_emp; DBMS_OUTPUT.PUT_LINE('加薪10%完成!'); else if rec_emp.job ='CLERK' and rec_emp.loc ='NEW YORK' then update emp set sal= sal*(1-0.05) where empno = rec_emp.empno; -- where current of cv_emp; DBMS_OUTPUT.PUT_LINE('减薪5%完成!'); endif; endif; endloop; end;
--验证过程 select empno ,e.job job, n.loc loc ,e.sal from emp e join newdept n on e.deptno = n.deptno and e.job = 'MANAGER'and n.loc = 'DALLAS'; --1 7566 MANAGER DALLAS 4275.00 --1 7566 MANAGER DALLAS 5653.69 select empno ,e.job job, n.loc loc,e.sal from emp e join newdept n on e.deptno = n.deptno and e.job = 'CLERK'and n.loc = 'NEW YORK'; --1 7934 CLERK NEW YORK 1300.00 --1 7934 CLERK NEW YORK 1433.25
--57.(使用游标更新行) 编写一PL/SQL,对所有的"销售员"(SALESMAN)增加佣金500. -- 1) 查询时使用 select .. from table where 条件 for update [of column [nowait]]子句锁定需要更新的行或列。 -- 2) update employee set sal=sal-2 where current of 游标; declare cursor cv_emp(p_job emp.job%type) isselect * from emp forupdateOF sal nowait; v_job emp.job%type; begin v_job:= '&请输入工作'; for rec_emp in cv_emp(v_job) loop update emp set comm= comm+500wherecurrentof cv_emp; --update employee set sal=sal-2 where current of 游标; endloop; end;
declare cursor cv_emp isselect * from emp orderby hiredate ; begin for rec_emp in cv_emp loop if cv_emp%rowcount <=2then update emp set job = 'HIGHTCLERK'where empno = rec_emp.empno; endif; endloop; end;
--方式二:游标方式 declare --游标选定job为CLERK 的员工,并按受雇时间 cursor cv_emp is select hiredate ,job from emp where job = 'CLERK'orderby hiredate forupdate ; begin for rec_emp in cv_emp loop if cv_emp%rowcount <3then--限制只修改两个 update new_scott set job = 'HIGHTCLERK'wherecurrentof cv_emp; endif; endloop; end;
select * from new_scott; /* 59. 对直接上级是'BLAKE'的所有员工,按照参加工作的时间加薪: 81年6月以前的加薪10% 81年6月以后的加薪5% */
declare cursor cv_emp isselect * from emp where mgr = (select empno from emp where ename = 'BLAKE'); begin for rec_emp in cv_emp loop if MONTHS_BETWEEN(rec_emp.hiredate,to_date('1981/6/1','yyyy/mm/dd'))>0then update emp set sal=sal*(1+0.05) where empno = rec_emp.empno; else update emp set sal=sal*(1+0.1) where empno = rec_emp.empno ; endif; endloop; end; --方式二:游标方法 declare cursor cv_emp(p_ename emp.ename%type) is select * from emp where mgr = (select empno from emp where ename = p_ename) forupdateof sal; v_ename emp.ename%type; begin v_ename:= '&上级姓名'; for rec_emp in cv_emp(v_ename) loop if MONTHS_BETWEEN(rec_emp.hiredate,to_date('1981/6/1','yyyy/mm/dd'))>0 then update emp set sal=sal*(1+0.05) wherecurrentof cv_emp; else update emp set sal=sal*(1+0.1) wherecurrentof cv_emp ; endif; endloop; end;
/*----------------------------------------------------第7章 过程和函数----------------------------------------------*/ /* 60. 编写一个给指定雇员加薪10%的过程:Raise_Sal(p_ename),这之后,检查如果已经雇佣该雇员超过60个月,则给他额外加薪3000. */ createorreplaceprocedure Raise_Sal(p_ename emp.ename%type) is cursor cv_rise(p_ename emp.ename%type) isselect * from emp where ename = p_ename forupdateof sal; cursor cv_emp is select * from emp where months_between(sysdate,hiredate)>60forupdateof sal;--后一部分 begin for emp in cv_rise(p_ename) loop update emp set sal=sal*(1+0.1) wherecurrentof cv_rise ; endloop;
for emp in cv_emp loop update emp set sal = sal+3000WHEREcurrentof cv_emp ; endloop; --commit; exception when others then rollback; dbms_output.put_line('操作有误,已经撤销!'); end;
--调用 declare v_ename emp.ename%type; begin v_ename:='&需要加薪的员工的名字:'; Raise_Sal(v_ename); end; --验证 select * from emp;
/* 61. 编写一个过程打印出99的乘法表。 */ createorreplaceprocedure pro_9_9 is
begin for i in1..9loop for j in1..i loop dbms_output.put(i||'*'||j||'='||i*j||' '); endloop; dbms_output.new_line; endloop; end;
--调用过程 begin pro_9_9; end; /* 62.编写一个过程完成两个数字的交换 */ createorreplaceprocedure date_change(no1 inoutint,no2 inoutinteger ) is v_temp int ; begin v_temp := no1; no1 := no2; no2 := v_temp; end; --调用 declare v_on1 int :=&请输入第一个数字; v_on2 int :=&请输入第二个数字; begin date_change(v_on1,v_on2); dbms_output.put_line('交换后:第一个数字:'||v_on1||' 第二个参数:'||v_on2); end;
--1.1建立交易表视图 createorreplaceview tra as select * from log_msg;
--1.2 建立开户过程 createorreplaceprocedure open_account(p_aname acc.aname%type,aid acc.idno%type,money acc.money%type, p_accountno out acc.ACCOUNTNO%type ) is v_rand number(20); v_num int default 0; v_account acc.ACCOUNTNO%type; id_has_exist exception; --该身份证已经开过户 name_has_exist exception; --该姓名已经注册 begin selectcount(*) into v_num fromaccwhere aid= idno; if v_num > 0 then raise id_has_exist; endif; selectcount(*) into v_num fromaccwhere ANAME= p_aname ; if v_num > 0 then raise name_has_exist; endif; select trunc(dbms_random.value*100000000,0) into v_rand from dual;--产生一个8位的随机数 v_account:=CONCAT('67226738',to_char(v_rand)); --根据前缀产生一个账号 p_accountno:=v_account; --作为返回值返回 insertintoaccvalues(v_account,p_aname,aid,money,sysdate); dbms_output.put_line(v_account||' '||p_aname||' '||aid||' '||money||' '||sysdate);--检验输出 commit; exception when id_has_exist then raise_application_error('-20012','该身份证已经开户,请换其他身份证继续!!'); when name_has_exist then raise_application_error('-20002','该客户已经存在,不能重名!!'); when others then rollback; raise_application_error('-20011','操作失败,已撤销!!'); end open_account;
--1.3 测试(------------------------------------------开户过程----------------------------------------) declare aname acc.aname%type; aid acc.idno%type; money acc.money%type; v_account acc.ACCOUNTNO%type;--记录返回账号 begin aname:='&开户姓名'; aid:='&身份证号'; money:=&余额; open_account(aname,aid,money,v_account); dbms_output.put_line('恭喜您开户成功!您的账户为:'||v_account); end ; select * fromacc;
--2.1 转账功能工程transaction createorreplaceprocedure pro_tract(p_fromaccount tra.FROMACCOUNT%type, p_toaccount tra.TOACCOURT%type,p_money tra.MONEY%type) is v_counter intdefault0; v_money tra.MONEY%type; no_found_from exception; no_found_to exception; no_enough exception; data_error exception; no_equals exception; begin if p_money<0then raise data_error; endif; selectcount(*) into v_counter fromaccwhere ACCOUNTNO = p_fromaccount; if v_counter = 0 then raise no_found_from; endif ; select money into v_money fromaccwhere ACCOUNTNO = p_fromaccount; if (v_money- p_money)<0 then raise no_enough; endif ;
selectcount(*) into v_counter fromaccwhere ACCOUNTNO = p_toaccount; if v_counter = 0 then raise no_found_to; endif ; if p_fromaccount = p_toaccount then raise no_equals; endif;
updateaccset money = money-p_money where acc.ACCOUNTNO = p_fromaccount; updateaccset money = money+p_money where acc.ACCOUNTNO = p_toaccount; insertinto tra(tradeno,fromaccount,toaccourt,money) values ( to_char('T10000-'||to_char(sq_tra_log.nextval)) ,p_fromaccount, p_toaccount,p_money);----------------------------------------- dbms_output.put_line('转账成功!'); commit; exception when no_found_from then raise_application_error('-20013','转出账户不存在!'); when no_found_to then raise_application_error('-20014','转入账户不存在!'); when no_enough then raise_application_error('-20015','转出账户余额不足!'); when data_error then raise_application_error('-20016','转账数额不能为负值!'); when no_equals then raise_application_error('-20030','转出账户与转入账户相同!'); when others then raise_application_error('-20017','操作失败,动作已撤销!'); rollback; end pro_tract;
select * fromacc; select * from tra; --2.2 测试(-------------------------------------------------转账过程测试----------------------------------) declare v_fromaccount tra.FROMACCOUNT%type; v_toaccount tra.TOACCOURT%type; v_money tra.MONEY%type; begin v_fromaccount :='&转账账号'; v_toaccount :='&收账账号'; v_money:=&转账金额; pro_tract(v_fromaccount,v_toaccount,v_money); commit; /* exception -- 加了这个异常后,raise_application_error 不在显示 when others then dbms_output.put_line('转账失败!');*/ end;
--2.3创建序列 createsequence sq_tra_log startwith999; --3.1 /* (3)根据转出账号和交易时间段 可查询转出账号的所有交易记录。最后还需要返回该时间段转出的总金额。 a)向“交易日志表”插入数据。 b)交易号的生成规则:'T10000-'||trans_seq.nextval --> T10000-1000 */ createorreplaceprocedure pro_search_trace(p_fromaccount tra.FROMACCOUNT%type, begintime date,endtime date, totalmoney out tra.MONEY%type) is cursor cv_accot is select * from tra where FROMACCOUNT = p_fromaccount and TRADETIME between begintime and endtime ; v_counter int default 0; time_error exception; no_found_from exception; begin if months_between(begintime ,endtime)>0then raise time_error; endif; selectcount(*) into v_counter from tra where FROMACCOUNT = p_fromaccount; if v_counter = 0 then raise no_found_from; endif ; totalmoney:=0; dbms_output.put_line(p_fromaccount||' 在 '||to_char(begintime, 'yyyy"年"mm"月"dd"日"')||' ~ '||to_char(endtime,'yyyy"年"mm"月"dd"日"')||' 时间段内的交易清单:'); dbms_output.new_line; for tra_accot in cv_accot loop totalmoney:=totalmoney+tra_accot.MONEY; dbms_output.put_line(tra_accot.tradeno||' '||tra_accot.fromaccount|| ' '||tra_accot.toaccourt||' '||to_char(tra_accot.money,'L999,999,999.00')||' '||to_char(tra_accot.tradetime,'yyyy"年"mm"月"dd"日"')); endloop; dbms_output.new_line; exception when time_error then raise_application_error('-20040','起始时间不能晚于结束时间!'); when no_found_from then raise_application_error('-20018','没有发现该账户的交易记录!'); when others then raise_application_error('-20019','查询异常!'); end pro_search_trace ;
--65. 基于账户表,编写一个函数通过账号获得账户余额;如果输入的账号不存在则显示相应的异常信息。 createorreplacefunction get_balance (accno acc.ACCOUNTNO%type) returnnumber is v_balance acc.MONEY%type; begin select money into v_balance fromaccwhere ACCOUNTNO = accno; return v_balance ; end; --- select get_balance('6722673861353700') from dual;
--66. 检测一个值是否落在了正常的员工工资范围内 createorreplacefunction check_sal (sal salgrade.losal%type) return varchar2 is v_losal salgrade.losal%type; v_hisal salgrade.losal%type; begin selectmin(losal)into v_losal from salgrade; selectmax(hisal) into v_hisal from salgrade; if sal>v_losal and sal < v_hisal then return '在正常工资范围!'; else return '不在正常工资范围!'; endif ; end;
select check_sal(690) from dual; select * from salgrade; --67. 编写一个函数获得指定部门的平均工资。
createorreplacefunction get_avg_sal(p_dname newdept.dname%type) returnnumber is v_avg new_scott.sal%type; v_counter int default 0; no_dept exception; begin selectcount(dname) into v_counter from newdept where p_dname=dname; if(v_counter=0) then raise no_dept; endif; selectavg(sal) into v_avg from new_scott where deptno = (select deptno from newdept where dname = p_dname); return v_avg; exception when no_dept then raise_application_error('-20048','不存在该部门'); end;
/*--------------------------------------------------(了解) 触发器 -------------------------------------------------------- 1. 什么是触发器:触发器在数据库里以独立的对象存储,它与存储过程和函数不同的是,存储过程与函数需要用户显示调用才执行, 而触发器是由一个事件来启动运行。即触发器是当某个事件发生时自动地隐式运行。并且,触发器不能接收参数。 所以运行触发器就叫触发或点火。 2. ORACLE事件指的是对数据库的表进行的INSERT、UPDATE及DELETE操作或对视图进行类似的操作。 3. 触发器不接受参数。 触发器组成: 1)触发事件:引起触发器被触发的事件。 例如:DML语句(INSERT, UPDATE, DELETE语句对表或视图执行数据处理操作)、 DDL语句(如CREATE、ALTER、DROP语句在数据库中创建、修改、删除模式对象)、数据库系统事件(如系统启动或退出、异常错误)、 用户事件(如登录或退出数据库)。 2)触发时间:即该TRIGGER 是在触发事件发生之前(BEFORE)还是之后(AFTER)触发,也就是触发事件和该TRIGGER 的操作顺序。 3)触发操作:即该TRIGGER 被触发之后的目的和意图,正是触发器本身要做的事情。 例如:PL/SQL 块。 4)触发对象:包括表、视图、模式、数据库。只有在这些对象上发生了符合触发条件的触发事件,才会执行触发操作。 5)触发条件:由WHEN子句指定一个逻辑表达式。只有当该表达式的值为TRUE时,遇到触发事件才会自动执行触发器, 使其执行触发操作。 6)触发频率:说明触发器内定义的动作被执行的次数。即语句级(STATEMENT)触发器和行级(ROW)触发器。 a)语句级(STATEMENT)触发器:是指当某触发事件发生时,该触发器只执行一次; b)行级(ROW)触发器:是指当某触发事件发生时,对受到该操作影响的每一行数据,触发器都单独执行一次。 REFERENCING 参照名称:OLD,NEW都是代表当前操作的记录行 1) 默认的相关名称分别为OLD和NEW,参照当前DML操作的新、旧列值 2) 触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句(触发条件)中则不能加冒号。 语法: create or replace trigger 触发器名 触发时间(BEFORE|AFTER) 触发事件(INSERT OR UPDATE OR DELETE) [of 列名] on 触发对象(表等) 触发频率 when (触发条件) declare --声明变量等 begin --执行部分 end 触发器名; */
--当更新或插入员工的奖金时,其奖金comm大于1000时,sal工资自动多加10元 createorreplacetrigger auto_raise_sal_trg beforeinsertorupdateof comm on employee foreachrow--表示行级触发器 when (NEW.comm>=1000) declare begin --触发器里预定义了三个操作条件 -- inserting,updating,deleting触发动作条件,其值为boolean,只能在触发器主体中使用 if inserting then --触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句(触发条件)中则不能加冒号。 :NEW.sal := :NEW.sal + 10; endif; if updating then :NEW.sal := :OLD.sal + 10; endif; end auto_raise_sal_trg;
--建表 test_trg droptable test_trg; createtable test_trg( tid varchar2(4) )
createsequence test_trg_seq startwith1;
--使用触发器为表在插入数据时生成一个id值:A序号(序号用序列生成) createtable test_id( tid varchar2(4) ) createsequence test_id_sq startwith1;
createorreplacetrigger auto_id beforeinserton test_id foreachrow when (new.tid isnull) declare v_id test_id.tid%type; begin select'A'||test_id_sq.nextval into v_id from dual; :new.tid := v_id; end;
-- insertinto test_id values('159'); select * from test_id;
insertinto employee(empno,ename,job,sal,comm,deptno) values(employee_seq.nextval,'小美','CLERK',4000.0,1000,10); update employee set comm=1500where ENAME='小美';
------------------------------------------------ select * from employee WHERE ENAME='小美'orderby empno DESC; select * from department; select * from salgrade;