数据库SQL基本操作

1、查询表结构

  desc 表名

2、显示当前连接用户

   show user

3、查看系统拥有哪些用户

   select * from all_users; 

4、查询当前用户下所有对象

   select * from tab;

5、回滚事务

   roll;

  rollback;

6、提交事务

  commit; 

 

 

1. 创建教材的学生-课程数据库中的三个表.定义表时请注意数据类型问题,Oracle的数据类型请参照本实验讲义.要求学号在20000000至99999999之间,年龄<29,性别只能是’男’或’女’,姓名非空。

create table student(

sno number(12) constraint pk_student primary key

                        constraint ck_sno check(sno>=20000000 and sno<=99999999),

sname char(20) not null constraint u_sname unique,

sage number(3) constraint ck_sage check(sage<29),

ssex char(2) constraint ck_ssex check(ssex=''  or ssex=''),

sdept char(10)

);

 

 

create table course(

cno number(4) constraint pk_course primary key,

cname char(20),

cpno number(4) constraint fk_cpno references course (cno),

ccredit number(4)

);

 

 

create table sc(

sno number(12) constraint ck_sno check(sno>=20000000 and sno<=99999999),

cno number(4),

grade number(3),

constraint pk_sc primary key(sno,cno),

constraint fk_sc foreign key(cno) references course(cno)

);

 

 

2.  修改学生-课程数据库的3个表的定义,分别为每个表建立主码和外码(如果有),并输入数据,验证实体完整性和参照完整性。

insert into student values(20140000,'哈哈',20,'','软件工程');

insert into student values(20140001,' hehe',20,'','软件工程')

insert into student values(20140002,' nike',19,'','软件工程')

 

 

insert into course values(10,'数据库',null,2);

insert into course values(11,'数据库2',null,2);

insert into course values(12,'数据库3',null,2);

insert into course values(13,'c++',10,2);

insert into course values(14,'java',12,3);

 

 

insert into sc values(20140000,10,99);

insert into sc values(20140001,11,98);

insert into sc values(20140002,10,99);

insert into sc values(20140003,11,98);

 

3.  建立部门表DEPT,要求部门名称Dname列取值唯一,部门编号Deptno列为主码;建立职工表EMP,要求每个职工的应发工资不得超过3000元。应发工资实际上就是实发工资列Sal与扣除项Deduct之和。

create table dept(


dname char(10) constraint u_dname unique,

deptno number(12) constraint pk_dept primary key

)

 

create table emp(

wage number(5) constraint ck_wage check(wage<=3000),

sal number(5),

deduct number(5)   --constraint ck_deduct check(deduct=wage-sal)
)
 

 

4. 对以上建立的表建立索引。

 

create unique index idx_student on student(sname);

create unique index idx_course on course(cname);

create unique index idx_sc on sc(sno);

create unique index idx_dept on dept(deptno);

create unique index idx_emp on emp(wage);

 

 

 
/*重建表*/
drop table sc cascade constraint; drop table student cascade constraint; drop table course cascade constraint; Create table Student (Sno number(8) Constraint ck_sno check (Sno>20000000 and sno<99999999) , Sname varchar2(8) not null, Ssex char(2), Sage number(2) Constraint ck_sage check (sage<29) , Sdept varchar2(20), Constraint ck_ss check (Ssex in ('','')), constraint PK_student primary key (sno)); Create table Course (Cno number(4) constraint pk_course primary key, Cname varchar2(20), Cpno number(2), Ccredit number(2)); Create table SC (Sno number(8), Cno number(4), Grade number(3), Constraint pk_SC Primary key (Sno,Cno), Constraint fk_s Foreign key (sno ) references student(Sno), Constraint fk_c Foreign key (cno ) references course(Cno) ); Insert Into Student(Sno,Sname,Ssex,Sage,Sdept) Values(20070001,'李佳','',20,'MA'); Insert Into Student(Sno,Sname,Ssex,Sage,Sdept) Values(20070002,'刘明','',19,'IS'); Insert Into Student(Sno,Sname,Ssex,Sage,Sdept) Values(20070003,'王添','',18,'MA'); Insert Into Student(Sno,Sname,Ssex,Sage,Sdept) Values(20070004,'张力','',21,'IS'); Insert Into Student(Sno,Sname,Ssex,Sage,Sdept) Values(20070005,'张力','',19,'CS'); Insert Into Student(Sno,Sname,Ssex,Sage,Sdept) Values(20070006,'张力','',19,'MA'); Insert Into Course(Cno,Cname,Cpno,Ccredit) Values(1,'数据库原理',5,2); Insert Into Course(Cno,Cname, Ccredit) Values(2,'数学',2); Insert Into Course(Cno,Cname,Cpno, Ccredit) Values(3,'信息系统',1,4); Insert Into Course(Cno,Cname,Cpno, Ccredit) Values(4,'操作系统',6,3); Insert Into Course(Cno,Cname,Cpno,Ccredit) Values(5,'数据结构',7,4); Insert Into Course(Cno,Cname,Ccredit) Values(6,'数据处理',2); Insert Into Course(Cno,Cname,Cpno,Ccredit) Values(7,'PASCAL语言',6,4); Insert Into SC(Sno,Cno, Grade) Values(20070001,1,92); Insert Into SC(Sno,Cno, Grade) Values(20070001,2,85); Insert Into SC(Sno,Cno, Grade) Values(20070001,3,88); Insert Into SC(Sno,Cno, Grade) Values(20070002,2,90); Insert Into SC(Sno,Cno, Grade) Values(20070002,3,80); Insert Into SC(Sno,Cno, Grade) Values(20070001,4,92); Insert Into SC(Sno,Cno, Grade) Values(20070001,5,85); Insert Into SC(Sno,Cno, Grade) Values(20070001,6,88); Insert Into SC(Sno,Cno, Grade) Values(20070003,2,90); Insert Into SC(Sno,Cno, Grade) Values(20070003,3,80); Insert Into SC(Sno,Cno, Grade) Values(20070001,7,92); Insert Into SC(Sno,Cno, Grade) Values(20070005,4,92); Insert Into SC(Sno,Cno, Grade) Values(20070003,1,85); Insert Into SC(Sno,Cno, Grade) Values(20070003,4,88); Insert Into SC(Sno,Cno, Grade) Values(20070002,1,90); Insert Into SC(Sno,Cno, Grade) Values(20070002,5,80); 二、数据查询,对实验一建立的学生-课程数据库中的表进行查询 1、查询学生的基本信息; select * from student; 2、查询“CS”系学生的基本信息; select * from student where sdept='CS'; 3、查询“CS”系学生年龄不在19到21之间的学生的学号、姓名; select sno,sname from student where sdept='CS' and ( sage <19 or sage >21 ); 4、找出最大年龄; select max(sage) from student; 5、找出“CS”系年龄最大的学生,显示其学号、姓名; select sno , sname from student where sdept='CS' and sage= (select max(sage) from student where sdept='CS') 6、找出各系年龄最大的学生的年龄; select sdept, max(sage) from student Group by sdept 7、统计“CS”系学生的人数; select count(*) from student where sdept='CS' 8、统计各系学生的人数,结果按升序排列; select sdept,count(*) from student group by sdept order by count(*) asc 9、按系统计各系学生的平均年龄,结果按降序排列; select sdept,avg(sage) from student group by sdept order by avg(sage) desc 10、查询每门课程的课程名; select cname from course 11、查询无先修课的课程的课程名和学时数; select cname,ccredit from course where cpno is null 12、统计无先修课的课程的学时总数; select count(*) from course where cpno is null 13、统计每位学生选修课程的门数、学分及其平均成绩; 统计选修每门课程的学生人数及各门课程的平均成绩; select sno,count(sc.cno),sum(ccredit),avg(grade) from sc,course where course.cno=sc.cno group by sno; select course.cno,count(sno),avg(grade) from course,sc where course.cno=sc.cno group by course.cno; 14、找出平均成绩在85分以上的学生,结果按系分组,并按平均成绩的升序排列; - select sc.sno,sdept,avg(grade) from sc,student where sc.sno=student.sno and (select avg(grade) from sc)>85 group by sc.sno,sdept order by avg(grade) asc 15、查询选修了“1”或“2”号课程的学生学号和姓名; select student.sno,student.sname from student,sc where student.sno=sc.sno and (1 in cno or 2 in cno) group by student.sno,student.sname 16、查询选修了课程名为“数据库系统”且成绩在60分以下的学生的学号、姓名和成绩; select student.sno,student.sname,grade from student,course,sc where course.cname='数据库原理' and grade<60 and student.sno=sc.sno and course.cno=sc.cno 17、查询每位学生选修了课程的学生信息(显示:学号,姓名,课程号,课程名,成绩); select student.sno,student.sname,course.cno,cname,grade from student,course,sc where student.sno=sc.sno and course.cno=sc.cno group by student.sno,student.sname,course.cno,cname,grade 18、查询没有选修课程的学生的基本信息; - select student.sno,sname,ssex,sage,sdept from student,sc where cno is null and student.sno=sc.sno group by student.sno,sname,ssex,sage,sdept 19、查询选修课程成绩至少有一门在80分以上的学生学号; select sno from sc where grade>80 group by sno 20、查询选修了3门以上课程的学生学号; select sno from sc s1 where (select count(cno) from sc s2 where s1.sno=s2.sno group by sno)>3 group by sno 21、查询选修课程成绩均在80分以上的学生学号; select sno from sc s1 where 80<all (select grade from sc s2 where s1.sno=s2.sno group by sno,grade) group by sno 三、 视图操作: 1、 定义“IS”系学生基本情况视图V_IS 并查询结果; create view V_IS as select SNO,SNAME,SSEX,SAGE,SDEPT from student where sdept='IS'; select * from V_IS; 2、 将S,C,SC表中学生的学号,姓名,课程号,课程名,成绩定义为视图V_S_C_G并查询结果; create view V_S_C_G as select s.sno,s.sname,c.cno,c.cname,grade from student s,course c,sc; select * from V_S_C_G; 3、 将各系学生人数,平均年龄定义为视图V_NUM_AVG并查询结果; create view V_NUM_AVG(sdept,count,avg) as select sdept,count(sno),avg(sage) from student group by sdept; select * from V_NUM_AVG; 4、 定义一个反映学生出生年份的视图V_YEAR并查询结果; create view V_YEAR(name,birth) as select sname,2016-sage from student select * from V_YEAR; 5、 将各位学生选修课程的门数及平均成绩定义为视图V_AVG_S_G并查询结果; create view V_AVG_S_G(sno,cno_count,grade_avg) as select sno,count(cno),avg(grade) from sc group by sno select * from V_AVG_S_G 6、 将各门课程的选修人数及平均成绩定义为视图V_AVG_C_G并查询结果; create view V_AVG_C_G(cno,count,avg) as select cno,count(sno),avg(grade) from sc group by cno select * from V_AVG_C_G 7、 建立视图V_AVG_A查询平均成绩为90分以上的学生学号、姓名和成绩; create view V_AVG_A(sno,sname,grade_avg) as select student.sno,sname,avg(grade) from student,sc where student.sno=sc.sno group by sno having avg(grade)>90 8、 建立视图V_AVG_B查询各课成绩均大于平均成绩的学生学号、姓名、课程和成绩; create view V_AVG_B as select student.sno,sname,s1.cno,s1.grade from student,sc s1,sc s0 where student.sno=s1.sno and s0.grade>all(select avg(grade) from sc s2 where s2.cno=s1.cno group by cno) group by student.sno,sname,s1.cno,s1.grade; /*SELECT Sno,Sname,Cname,Grade FROM V_S_C_G vscg WHERE NOT EXISTS (SELECT Sno,Sname,V_S_C_G.Cno,Cname,Grade,avg_grade FROM V_S_C_G,V_AVG_C_G WHERE V_S_C_G.Cno = V_AVG_C_G.Cno AND Grade < avg_grade AND vscg.Sno = V_S_C_G.Sno);*/ 9、 建立视图V_AVG_C按系统计各系平均成绩在80分以上的人数,结果按降序排列; create view V_AVG_C(sc_sno,sdept,avg) as select sc.sno,sdept,avg(grade) from sc,student where sc.sno=student.sno and (select avg(grade) from sc)>80 group by sc.sno,sdept order by avg(grade) desc 10、 通过视图V_IS,分别将学号为“S1”和“S4”的学生姓名更改为“S1_MMM”,”S4_MMM” 并查询结果; create view V_IS as select * from student; update V_IS set sname='S1_MMM' where sno=20070001; update V_IS set sname='S4_MMM' where sno=20070004; 11、 通过视图V_IS,新增加一个学生记录 (‘S12’,’YAN XI’,19,’IS’),并查询结果; insert into V_IS(sno,sname,sage,sdept) values(20421412,'YAN XI',19,'IS') select * from V_IS 12、 通过视图V_IS,新增加一个学生记录 ('S13','YAN XI',19,'MA'),并查询结果; insert into V_IS(sno,sname,sage,sdept) values(20421413,'YAN XI',19,'MA') select * from V_IS 13、 通过视图V_IS,删除学号为“S12”和“S3”的学生信息,并查询结果; delete from V_IS where sno=20421412 or sno=20070003 select * from V_IS

 

 

 

 

1 利用 LOOP 循环方式计算 1+3+5+7+9。代码如下: 
   SET SERVEROUTPUT ON 
   DECLARE 
     i NUMBER; 
     sum1 NUMBER; 
   BEGIN 
     i:=1; 
     sum1:=0; 
     LOOP 
        IF mod(i,2)!=0 THEN 
           sum1:=sum1+i; 
        END IF; 
        i:=i+1; 
        IF(i>9) THEN 
          EXIT; 
        END IF; 
     END LOOP; 
     DBMS_OUTPUT.PUT_LINE(sum1); 
   END; 



SET SERVEROUTPUT ON 
    DECLARE
    E_name emp.ename%type;
    E_no emp.empno%type;
    E_sal emp.sal%type;
    E_deptno emp.deptno%type;
    E_hiredate emp.hiredate%type;
    BEGIN
        select empno,ename,hiredate,sal,deptno  INTO E_no,E_name,E_hiredate,E_sal , E_deptno FROM emp WHERE empno='7788';
    DBMS_OUTPUT.PUT_LINE(E_no||'姓名是:'||E_name ||'入职日期:'||E_hiredate ||'工资为:'||E_sal || E_deptno);
    end;  




3.检索工资大于700的员工工资并输出,同时对可能发生的异常进行处理。
declare
   v_sal emp.sal%type;
begin
   select sal into v_sal from emp where sal>=700;
exception
   when  no_data_found  then
         dbms_output.put_line('no data!');
   when too_many_rows then
         dbms_output.put_line('too many row');
   when others  then
         null;
end;






4.编写PL/SQL程序块,完成如下功能:输入一个员工号,修改该员工的工资,如果该员工为10号部门,工资增加100;若为20号部门,工资增加160;若为30号部门,工资增加200;否则增加300。用if 和case  结构实现。
/*if*/
set serveroutput on
declare
    v_eno emp.empno%TYPE:=&empno;
    v_esal emp.sal%TYPE;
    v_edept emp.deptno%TYPE;
begin
    select deptno into v_edept from emp where v_eno=empno;
    if v_edept=10
    then update emp set sal=sal+100 where v_eno=empno;
    elsif v_edept=20
    then update emp set sal=sal+160 where v_eno=empno;
    elsif v_edept=30
    then update emp set sal=sal+200 where v_eno=empno;
    else
    update emp set sal=sal+300 where v_eno=empno;
    end if;
end;
/*case*/
set serveroutput on
declare
    v_eno emp.empno%TYPE:=&empno;
    v_esal emp.sal%TYPE;
    v_edept emp.deptno%TYPE;
begin
    select deptno into v_edept from emp where v_eno=empno;
    case
        when v_edept=10
            then update emp set sal=sal+100 where v_eno=empno;
        when v_edept=20
            then update emp set sal=sal+160 where v_eno=empno;
        when v_edept=30
            then update emp set sal=sal+200 where v_eno=empno;
        else
      update emp set sal=sal+300 where v_eno=empno;    
      end case;
end;







5.用3种循环语句来实现将1到50,50个数输入到某个表中。
create table num(
num number(10)
);
 /*case1*/
set SERVEROUTPUT ON;
declare
  v_num num.num%TYPE;
begin
  v_num:=0;
  loop 
  v_num:=v_num+1;
  insert into num values(v_num);
  exit when v_num=50;
  end loop;
end;

/*case2*/
set SERVEROUTPUT ON;
declare
  v_num num.num%TYPE;
begin
  v_num:=0;
  while v_num<50 loop 
  v_num:=v_num+1;
  insert into num values(v_num);
  end loop;
end;

/*case3*/
set SERVEROUTPUT ON;
declare
  v_num num.num%TYPE;
begin
  for v_num in 0..50 loop
  insert into num values(v_num);
  end loop;
end;







6.系统的自定义异常
查询某个部门的平均工资,如果此工资没有在2000~3000之间,触发自定义异常,请编写PL/SQL来处理此异常。并输出“此部门的平均工资不在2k到3k之间”。 如果你能给此自定义异常分配一个异常号,及异常名(昵称),那自然是极好的。如果不能,也没关系。
set SERVEROUTPUT ON
declare 
v_avg emp.sal%TYPE;
e_salout exception;
begin
  select avg(sal) into v_avg from emp;
  if v_avg < 2000 or v_avg > 3000 
  then raise e_salout;
  end if;
  exception
  when e_salout
  then dbms_output.put_line('此部门的平均工资不在2k到3k之间');
end;   

 

 

1.操作职工号为7788的职工信息,如果存在该职工,修改他的工资,如果没有匹配则插入一新行。(隐式游标的应用).
set serveroutput on
begin
update emp set sal=sal+100 where emp.empno=7788;
if sql%notfound then 
insert into emp(empno,ename,job,mgr,sal,comm,deptno) values(7778,"strstr","analyst",7566,3640,0,20);
end if;
end;
 



2. 游标变量的应用,阅读并执行下列代码,体会游标变量的应用。
PL/SQL中,可以声明游标变量,在运行时刻设置游标对应的查询语句,可以动态实现查询。游标变量的使用步骤如下:
 1)声明游标变量:TYPE  type_name  IS REF CURSOR  RETURN  return_type;
2)打开游标变量: 如果要将一个游标变量与一个特定的select 语句关联,则需 Open 将其打开,语法如下:OPEN  cursor_variable  FOR select_statements;
3)循环处理游标的内容。
4)关闭游标变量:   CLOSE  cursor_variable;
游标变量的应用:使用同一游标打开多个查询
create or replace procedure  print_emp as
  type rc is ref cursor;
  v_rc rc;
  v_emp emp%rowtype;
  v_ename varchar2(40);
  v_dname varchar2(40);
  v_loc varchar2(40);
begin
   open v_rc for select  * from emp order by job;
   dbms_output.put_line('           雇员信息     ' );
   dbms_output.put_line(' ======================');
   dbms_output.put_line(' 序号    姓名   职务   薪水');
   loop 
     fetch v_rc into v_emp;
    exit when v_rc%NOTFOUND;
      dbms_output.put_line(rpad(to_char(v_rc%ROWCOUNT),8,' ')||rpad(V_emp.ename,10,' ')|| rpad(V_emp.job,10,' ')|| rpad(V_emp.sal,10,' '));
  end loop;

  open v_rc for select ename,dname,loc from emp,dept 
      where emp.deptno=dept.deptno order by dname;
     dbms_output.put_line('        工作信息     ' );
   dbms_output.put_line(' =======================');
   dbms_output.put_line(' 序号   姓名      部门     地点');
   loop 
     fetch v_rc into v_ename,v_dname,v_loc;
    exit when v_rc%NOTFOUND;
      dbms_output.put_line(rpad(to_char(v_rc%ROWCOUNT),8,' ')||rpad(V_ename,12,' ')|| rpad(V_dname,12,' ')|| rpad(V_loc,10,' '));
  end loop;
   close v_rc;
end  print_emp;
3.游标参数的应用。并执行下列代码,输入不同的参数值,体会游标参数的应用。
游标的SELECT语句没有WHERE子句,或者用WHERE子句指定了一个固定的条件,这样每次都查询同样的数据。在更多的情况下,可能要根据实际情况查询不同的数据。为了通过游标对数据进行更加灵活的处理,可以为游标定义参数,这些参数可以用在WHERE子句中。在打开游标时,指定实际的参数值,这样游标在每次打开时,可以根据不同的实际参数值,返回所需的不同数据。
定义带参数的游标的语法格式为:
DECLARE   CURSOR 游标名(参数1, 参数2, ...)    IS    SELECT语句;
其中参数的定义方法与子程序中的参数定义完全相同,可以指定默认值。在用OPEN命令打开游标时,要向游标提供实际参数,游标根据提供的参数值,查询符合条件的数据。打开游标的语法格式为:
OPEN游标名(实际参数1, 实际参数2...)
阅读下面的查询
例子:
DECLARE  
  CURSOR cur_6(d_no IN emp.deptno%type, min_sal IN emp.sal%type := 1000) IS SELECT ename, sal, hiredate FROM emp WHERE deptno = d_no and sal >= min_sal;  
  e cur_6%rowtype;  
BEGIN  
  if not cur_6%ISOPEN then  
    --如果游标没有打开,则打开它    
    open cur_6(20, 2000);  
  END if;  
  fetch cur_6  
    INTO e; --取出第一行数据    
  while cur_6%found loop  
    dbms_output.put_line('姓名:' || e.ename || '工资:' || e.sal ||  
                         ' 工作时间:' || e.hiredate);  
    fetch cur_6  
      INTO e;  
  END loop;  
  dbms_output.put_line('员工总数:' || cur_6%rowcount); --获取的总行数    
  close cur_6; --关闭游标    
END;  
4. 编写程序利用3种循环统计并输出各个部门的平均工资。

--case1
set serveroutput on
declare 
v_sal emp.sal%type;
v_deptno emp.deptno%type;
v_cnt10 number;v_cnt20 number;v_cnt30 number;
v_sum10 number;v_sum20 number;v_sum30 number;
v_avg10 number;v_avg20 number;v_avg30 number;
cursor c_emp is select sal,deptno from emp;

begin
if (not c_emp%isopen)then
open c_emp;
end if;

v_sum10:=0;v_sum20:=0;v_sum30:=0;
v_cnt10:=0;v_cnt20:=0;v_cnt30:=0;
loop 
fetch c_emp into v_sal,v_deptno;
exit when c_emp%notfound;
if v_deptno = 10 then
v_cnt10:=v_cnt10+1;
v_sum10:=v_sum10+v_sal;
end if;
if v_deptno = 20 then
v_cnt20:=v_cnt20+1;
v_sum20:=v_sum20+v_sal;
end if;
if v_deptno = 30 then
v_cnt30:=v_cnt30+1;
v_sum30:=v_sum30+v_sal;
end if;
end loop;

v_avg10:=v_sum10/v_cnt10;
v_avg20:=v_sum20/v_cnt20;
v_avg30:=v_sum30/v_cnt30;

dbms_output.put_line('deptno    '||'avg_sal');
dbms_output.put_line('10        '||v_avg10);
dbms_output.put_line('20        '||v_avg20);
dbms_output.put_line('30        '||v_avg30);
end;


--case2
set serveroutput on
declare 
v_sal emp.sal%type;
v_deptno emp.deptno%type;
v_cnt10 number;v_cnt20 number;v_cnt30 number;
v_sum10 number;v_sum20 number;v_sum30 number;
v_avg10 number;v_avg20 number;v_avg30 number;
cursor c_emp is select sal,deptno from emp;

begin
if (not c_emp%isopen)then
open c_emp;
end if;

v_sum10:=0;v_sum20:=0;v_sum30:=0;
v_cnt10:=0;v_cnt20:=0;v_cnt30:=0;
fetch c_emp into v_sal,v_deptno;
while c_emp%found loop
if v_deptno = 10 then
v_cnt10:=v_cnt10+1;
v_sum10:=v_sum10+v_sal;
end if;
if v_deptno = 20 then
v_cnt20:=v_cnt20+1;
v_sum20:=v_sum20+v_sal;
end if;
if v_deptno = 30 then
v_cnt30:=v_cnt30+1;
v_sum30:=v_sum30+v_sal;
end if;
fetch c_emp into v_sal,v_deptno;
end loop;

v_avg10:=v_sum10/v_cnt10;
v_avg20:=v_sum20/v_cnt20;
v_avg30:=v_sum30/v_cnt30;

dbms_output.put_line('deptno    '||'avg_sal');
dbms_output.put_line('10        '||v_avg10);
dbms_output.put_line('20        '||v_avg20);
dbms_output.put_line('30        '||v_avg30);
end;

--case3
set serveroutput on
declare 
v_sal emp.sal%type;
v_deptno emp.deptno%type;
v_cnt10 number;v_cnt20 number;v_cnt30 number;
v_sum10 number;v_sum20 number;v_sum30 number;
v_avg10 number;v_avg20 number;v_avg30 number;
cursor c_emp is select sal,deptno from emp;

begin
v_sum10:=0;v_sum20:=0;v_sum30:=0;
v_cnt10:=0;v_cnt20:=0;v_cnt30:=0;
for v_row in c_emp loop
if v_row.deptno = 10 then
v_cnt10:=v_cnt10+1;
v_sum10:=v_sum10+v_row.sal;
end if;
if v_row.deptno = 20 then
v_cnt20:=v_cnt20+1;
v_sum20:=v_sum20+v_row.sal;
end if;
if v_row.deptno = 30 then
v_cnt30:=v_cnt30+1;
v_sum30:=v_sum30+v_row.sal;
end if;
end loop;

v_avg10:=v_sum10/v_cnt10;
v_avg20:=v_sum20/v_cnt20;
v_avg30:=v_sum30/v_cnt30;

dbms_output.put_line('deptno    '||'avg_sal');
dbms_output.put_line('10        '||v_avg10);
dbms_output.put_line('20        '||v_avg20);
dbms_output.put_line('30        '||v_avg30);
end;

 

 

1.编写过程,打印全体雇员信息PrintEmpRecord。
set serveroutput on;
create or replace procedure PrintEmpRecord as
v_emp emp%rowtype;
cursor cs is select * from emp; 
begin
if not cs%isopen then
open cs;
end if;
fetch cs into v_emp;
while cs%found loop
dbms_output.put_line(rpad(to_char(cs%rowcount),8,' ')||rpad(v_emp.ename,10,' ')||rpad(to_char(v_emp.empno),10,' ')||rpad(v_emp.job,10,' ')||rpad(to_char(v_emp.sal),10,' ')||rpad(to_char(v_emp.hiredate),16,' '));
fetch cs into v_emp;
end loop;
close cs;
end PrintEmpRecord;
exec PrintEmpRecord;


2.把雇员编号empno作为参数,设计过程SearchEmp查询并打印该雇员信息。
set serveroutput on;
create or replace procedure SearchEmp(p_empno in emp.empno%type) as
v_emp emp%rowtype;
begin
select * into v_emp from emp where empno = p_empno;
dbms_output.put_line(rpad(v_emp.ename,10,' ')||rpad(to_char(v_emp.empno),10,' ')||rpad(v_emp.job,10,' ')||rpad(to_char(v_emp.sal),10,' ')||rpad(to_char(v_emp.hiredate),16,' '));
exception
when no_data_found then
dbms_output.put_line('no_data_found');
end SearchEmp;


3. 创建一个存储过程,以部门号为参数,查询该部门的平均工资,并输出该部门中比平均工资高的员工号、员工名。
create or replace procedure dept_mt_avg(p_deptno in emp.deptno%type) as
cursor cs is select ename,empno from emp where deptno = p_deptno and sal>(select avg(sal) from emp where deptno = p_deptno group by deptno);
begin
for v_emp in cs loop
dbms_output.put_line(v_emp.ename||'    '||v_emp.empno);
end loop;
end  dept_mt_avg;
exec dept_mt_avg(10);


4. 创建一个存储过程,以部门号为参数,返回该部门的人数和最高工资。
create or replace procedure dept_maxSal_count(p_deptno in emp.deptno%type) as
cursor cs is select count(*) count,max(sal) max_sal from emp where deptno = p_deptno;
begin
for v_emp in cs loop
dbms_output.put_line(v_emp.count||'  '||v_emp.max_sal);
end loop;
end dept_maxSal_count;
exec dept_maxSal_count(10);


5.创建一个以部门号为参数,返回该部门最高工资的函数。
create or replace function dept_maxSal(p_deptno in emp.deptno%type) return number as
v_sal emp.sal%type;
begin
select max(sal) into v_sal from emp where deptno = p_deptno;
return v_sal;
end;

select dept_maxSal(10) from dual;



6.设计一个函数,实现按雇员编号empno得到雇员的新的工资额。新的工资的计算方法为参加工作5年以下的,工资上涨5%;参加工作6-10年的,工资上涨8%;参加工作11-15年的,工资上涨10%;参加工作16-20年的,工资上涨15%;参加工作20年以上的,工资上涨20%CREATE OR REPLACE FUNCTION NewSal( v_empno emp.deptno%TYPE )
RETURN emp.sal%TYPE
AS
v_newsal emp.sal%TYPE := 0;
v_sysdate DATE;
v_hiredate emp.hiredate%TYPE;
v_workdate NUMBER;

BEGIN
 SELECT hiredate INTO v_hiredate FROM emp
                                  WHERE empno = v_empno;
 SELECT SYSDATE() INTO v_sysdate FROM DUAL;
 SELECT v_sysdate - v_hiredate INTO v_workdate FROM DUAL;
 
SELECT sal INTO v_newsal FROM emp WHERE empno = v_empno;
 
 IF v_workdate < 365*5 THEN
  v_newsal := v_newsal * 1.05;
 ELSIF v_workdate BETWEEN 365*6 AND 365*10 THEN
  v_newsal := v_newsal * 1.08;
 ELSIF v_workdate BETWEEN 365*11 AND 365*15 THEN
  v_newsal := v_newsal * 1.1;
 ELSIF v_workdate BETWEEN 365*16 AND 365*20 THEN
  v_newsal := v_newsal * 1.15;
 ELSE
  v_newsal := v_newsal * 1.20;
 END IF;
 RETURN v_newsal;

END;

DECLARE
BEGIN
 dbms_output.put_line( Newsal( &empno ) );
END;

 

 

1)      为emp表创建一个触发器,当执行插入操作时,统计操作后员工人数;当执行更新工资操作时,统计更新后员工平均工资;当执行删除操作时,统计删除后各个部门的人数
 CREATE OR REPLACE TRIGGER trg_emp_dml 
AFTER INSERT OR UPDATE OR DELETE ON emp 
DECLARE
  v_count NUMBER;
  v_sal   NUMBER(6,2);
BEGIN
  IF INSERTING THEN 
    SELECT count(*) INTO v_count FROM emp;
    DBMS_OUTPUT.PUT_LINE(v_count);
  ELSIF UPDATING THEN
    SELECT avg(sal) INTO v_sal FROM emp;
    DBMS_OUTPUT.PUT_LINE(v_sal);
  ELSE
    FOR v_dept IN (SELECT deptno,count(*) num FROM emp 
                                                   GROUP BY deptno) LOOP
      DBMS_OUTPUT.PUT_LINE(v_dept.deptno||' '||v_dept.num);
    END LOOP;
  END IF;
END trg_emp_dml; 

(2)    为emp表创建一个触发器,修改员工工资时,保证修改后的工资高于修改前的工资。
CREATE OR REPLACE TRIGGER trg_emp_update_row 
BEFORE UPDATE OF sal ON emp 
FOR EACH ROW
WHEN(new.sal<=old.sal)
BEGIN
 RAISE_APPLICATION_ERROR
(-20001,'The salary is lower!');
END trg_emp_update_row; 

(3)    创建一个包括员工及其所在部门信息的视图empdept,然后向视图中插入一条记录(2345,’TOM’,3000,’SALES’)。 
CREATE OR REPLACE VIEW empdept 
AS
SELECT empno,ename,sal,dname 
FROM emp,dept WHERE emp.deptno=dept.deptno  
WITH CHECK OPTION;
INSERT INTO empdept 
VALUES(2345, 'TOM',3000, 'SALES');
*
ERROR 位于第 1 行:
ORA-01733: 此处不允许虚拟列 
CREATE OR REPLACE TRIGGER trig_view 
INSTEAD OF INSERT ON empdept 
FOR EACH ROW
DECLARE
 v_deptno dept.deptno%type;
BEGIN
SELECT deptno INTO v_deptno 
 FROM dept WHERE dname=:new.dname;
INSERT INTO emp(empno,ename,sal,deptno)   
 VALUES(:new.empno,:new.ename,v_deptno,:new.sal);
END trig_view; 

(4)创建一个系统级别触发器,记录所有用户的数据库访问时间。 
将每个用户的登录信息写入temp_table表中。
CREATE OR REPLACE TRIGGER log_user_connection 
AFTER LOGON ON DATABASE
BEGIN
  INSERT INTO scott.temp_table   VALUES (user,sysdate);
END log_user_connection; 

4.如何在 Oracle中实现类似自动增加 ID的功能 
   Oracle本身并未提供像 Access中的自动编号类型,但同样也可以实现类似自动增加 ID的功能,即字段值自动增长并自动插入到字段中,这时需要借助序列和触发器共同来实现。  
  例如,水果表“fruit”中有两个字段“num”、“name”,分别记录序号和水果的名称,第一个字段值随着第二个字段值的插入自动按顺序添加并插入。 
   CREATE TABLE fruit 
   (  num VARCHAR2(10) PRIMARY KEY, 
      name VARCHAR2(10) 
   ); 
  首先,创建一个序列 NUM。 
   CREATE SEQUENCE num  
   INCREMENT BY 1  
 START WITH 1 MAXVALUE 9999 MINVALUE 1  
   NOCYCLE  
       CACHE 20  
   ORDER; 
 其次,创建一个触发器。 
   CREATE TRIGGER fruit_tri  
   BEFORE INSERT ON fruit 
   FOR EACH ROW 
   BEGIN 
       SELECT TO_CHAR(NUM.nextval) INTO :NEW.num FROM DUAL; 
   //将序列的下一个取值存储到 fruit 表中的“name”字段,DUAL 为系统表 
   END; 
插入新记录后再查看“fruit”表中的现有记录。 
   INSERT INTO fruit(name) VALUES(‘菠萝’); 
   SELECT * FROM fruit; 

 

 

posted @ 2016-03-31 19:06  Shentr  阅读(574)  评论(0编辑  收藏  举报
http://www.cnblogs.com/shentr/