(Oracle) 语句练习 (数据表对象,PL/SQL游标、存储过程、函数)

(Oracle) 语句练习 (数据表对象,PL/SQL游标、存储过程、函数)

创建数据表

某数据库中包含科室表和医生表。

科室表:dept_table(deptno, dname, loc)

表中属性列依次是科室编号、科室名称、科室所在地。

科室表结构如下:

列名 数据据类型 长度 完整性约束
deptno char 8 主键(deptno_pk)
dname varchar2 24 唯一(dname_uk)
loc varchar2 36
create table dept_table(
    deptno char(8),
    dname varchar(24),
    loc varchar(36),
    constraint deptno_pk primary key(deptno),	-- 主键约束
    constraint dname_uk unique(dname)			-- 唯一性约束
);

医生表:doctor_table(docno, docname, age, sal, deptno)

表中属性列依次是医生编号、医生姓名、年龄、工资、所在科室编号。

医生表结构如下:

列名 数据类型 长度 完整性约束
docno char 8 主键(docno_pk)
docname varchar2 10 非空
age int 年龄在18~55岁(age_ck)
sal number
deptno char 8 外键(参照dept_table中的deptno)(deptno_fk)
create table doctor_table(
    docno char(8),
    docname varchar(10) not null,
    age int,
    sal number,
    deptno char(8),
    constraint docno_pk primary key(docno),	-- 主键约束
    constraint age_ck check(age between 18 and 55),	-- check约束
    constraint deptno_fk foreign key(deptno) references dept_table(deptno)	-- 外键约束
);

数据请自行插入,再练习下方习题

此处为补充的模拟数据,因为我很久没用Oracle了,所以是用mysql写的,可能会出问题,请读者自己甄别

-- dept_table表的数据
INSERT INTO `dept_table` VALUES ('01', '口腔科', '1楼');
INSERT INTO `dept_table` VALUES ('02', '外科', '2楼');
INSERT INTO `dept_table` VALUES ('03', '内科', '2楼');
INSERT INTO `dept_table` VALUES ('04', '耳鼻科', '2楼');
INSERT INTO `dept_table` VALUES ('05', '呼吸科', '1楼');
INSERT INTO `dept_table` VALUES ('06', '儿科', '3楼');
INSERT INTO `dept_table` VALUES ('07', '血液科', NULL);
INSERT INTO `dept_table` VALUES ('08', '神经外科', NULL);
INSERT INTO `dept_table` VALUES ('09', '皮肤科', NULL);
INSERT INTO `dept_table` VALUES ('10', '骨科', NULL);
INSERT INTO `dept_table` VALUES ('11', '妇科', NULL);
INSERT INTO `dept_table` VALUES ('12', '消化科', NULL);

-- doctor_table表的数据
INSERT INTO `doctor_table` VALUES ('01', '张三', 30, 5000, '01');
INSERT INTO `doctor_table` VALUES ('02', '李四', 30, 8000, '01');
INSERT INTO `doctor_table` VALUES ('03', '王五', 32, 900, '02');
INSERT INTO `doctor_table` VALUES ('04', '赵六', 36, 12000, '03');
INSERT INTO `doctor_table` VALUES ('05', '孙七', 29, 8000, '02');
INSERT INTO `doctor_table` VALUES ('06', '张医生', 33, 1000, '10');
INSERT INTO `doctor_table` VALUES ('07', '李医生', 33, 1900, '08');
INSERT INTO `doctor_table` VALUES ('08', '王医生', 36, 2000, '10');
INSERT INTO `doctor_table` VALUES ('09', '赵医生', 39, 18000, '10');
INSERT INTO `doctor_table` VALUES ('10', '孙医生', 29, 1000, '02');

维护数据表

根据各表结构,用SQL语句完成下列操作。

1)将医生表doctor_table中的docname列的数据类型修改为char(20)。

-- 修改约束 modify
alter table doctor_table modify docname char(20);

2)doctor_table表中添加一个名为chk_sal的约束,从而保证医生的工资必须大于800。

-- 添加约束 add
alter table doctor_table add constraint chk_sal check(sal > 800);

3)将张三医生的工资调高20%。

-- 更新操作 update set
update doctor_table set sal = sal*1.2 where docname = '张三';

4)删除科室号为10,工资低于2000的医生信息。

-- 删除操作 delete
delete from doctor_table where deptno=10 and sal<2000;

5)查询各个科室的科室名称及其医生人数

查询结果按照医生人数的升序排列

如果人数相同,按照科室名称降序排列。

-- asc 升序(默认)
-- desc降序
select dname, b.cnt from dept_table a, (
    select deptno, count(*) as cnt
    from doctor_table
    group by deptno
) b
where a.deptno = b.deptno
order by b.cnt asc, dname desc;

6)查询各科室中至少有2个人工资在2500以上的科室号和医生人数。

select a.deptno, count(*) 
from doctor_table a, (
    select deptno 
    from doctor_table 
    where sal>2500
    group by deptno
    having count(*) >= 2
) b
where a.deptno = b.deptno
group by a.deptno;

7)查询平均工资超过3000的科室编号。

select deptno from doctor_table group by deptno having avg(sal)>3000;

8)查询孙七医生所在的科室名称及科室地点。

select dname, loc 
from dept_table 
where deptno = (
	select deptno 
    from doctor_table 
    where docname='孙七'
);

9)查询姓赵的医生的姓名、年龄和所在科室名称。

-- '_'单个字符
-- '%'零个或多个
select docname, age, dname 
from doctor_table a, dept_table b 
where a.deptno = b.deptno and a.docname like '赵%';

10)建一个“口腔科”科室的视图dept_10,包括医生编号、医生姓名及工资。

-- 视图关键词view
create view dept_10 as
select docno, docname, sal 
from doctor_table a, dept_table b 
where a.deptno = b.deptno and dname='口腔科';

(3)PL/SQL 练习

循环练习

计算1到100的偶数和,输出1~100的偶数和为:?

以下列出三种循环方式

PS:

  • %不是取余操作
  • sum是关键词
  • dbms_output.put_line('1~100的偶数和为:'||sum_i); 中||左右不要加空格
set serveroutput on
declare
    i number := 1;
    sum_i number := 0;
begin
    loop
        if mod(i, 2) = 0 then
            sum_i := sum_i + i;
        end if;
        i := i+1;
        exit when i > 100;
    end loop;
    dbms_output.put_line('1~100的偶数和为:'||sum_i);
end;
/
set serveroutput on
declare
    i number := 1;
    sum_i number := 0;
begin
    while i <= 100 loop
        if mod(i, 2) = 0 then
            sum_i := sum_i + i;
        end if;
    i := i+1;
    end loop;
    dbms_output.put_line('1~100的偶数和为:'||sum_i);
end;
/
set serveroutput on
declare
    sum_i number := 0;
    -- for 内部声明i,不用在这里declare
begin
    for i in 1..100 loop
        if mod(i, 2) = 0 then
            sum_i := sum_i + i;
        end if;
    end loop;
    dbms_output.put_line('1~100的偶数和为:'||sum_i);
end;
/

游标练习

带参数的游标实现查询某部门员工的工号和姓名。

-- 游标,书P166
set serveroutput on
declare
	-- 申明游标
    cursor cur_emp(v_dept in varchar2) is 
    -- 注意用户模式
    -- scott模式,书P83
    select * from scott.emp 
    where deptno = v_dept;
    v_emp scott.emp%rowtype;
begin
	-- 此处以部门号为10举例
	-- 打开游标
    open cur_emp(10);
    -- 类于高级语言的do-while循环
    loop
   		-- 读取游标
        fetch cur_emp into v_emp;
        dbms_output.put_line(v_emp.empno||','||v_emp.ename);
        exit when cur_emp%notfound;
    end loop;
    -- 关闭游标
    close cur_emp;
end;
/

存储过程、函数 练习

存储过程procedure 书P87

用存储过程实现根据给定的部门编号返回该部门的详细信息

-- in 表示输入类型参数(默认)
-- out表示输出参数类型
-- 书P190
create or replace procedure pr_dept (
    v_deptno in dept_table.deptno%type,
    v_dname out dept_table.dname%type,
    v_loc out dept_table.loc%type
) is
begin
    select dname, loc into v_dname, v_loc 
    from dept_table 
    where deptno = v_deptno;
end;
/

-- 执行操作,书P193
variable p_dname varchar2(24);
variable p_loc varchar2(36);
execute pr_dept('10', :p_dname, :p_loc);
-- 两种打印方式
print p_dname p_loc;
select :p_dname, :p_loc from dual;

创建一个存储过程,根据给定的部门,返回该部门员工的工资总和。

create or replace procedure pr_dept2 (
    v_deptno in dept_table.deptno%type,
    p_sum out number
) is
begin
    select sum(doctor_table.sal) into p_sum
    from dept_table, doctor_table
    where dept_table.deptno = doctor_table.deptno 
        and dept_table.deptno = v_deptno;
end;
/

-- 执行操作
variable p_sum number;
execute pr_dept2('10', :p_sum);

print p_sum;
select :p_sum from dual;

函数function 书P197

创建一个函数,根据给定的部门,返回该部门员工的工资总和。

-- 函数与存储过程的主要区别是函数具有返回值
create or replace function fun_dept3 (
    v_deptno in dept_table.deptno%type
) return number is
-- 申明内部变量
p_sum  number;
begin
    select sum(doctor_table.sal) into p_sum
    from dept_table, doctor_table
    where dept_table.deptno = doctor_table.deptno 
        and dept_table.deptno = v_deptno ;
    return p_sum;
end;
/

--调用
select fun_dept3('10') from dual;



以上提及的书本为 清华大学出版社 《Oracle从入门到精通》

你可能感兴趣的:(数据库,数据库,oracle,sql)