oracle数据库函数

前言,因为本人的工作,会使用到oracle数据库,并且是在虚拟机环境下运行的,所以写的不好,请大家谅解。

一、数字函数

1.绝对值abs(x),算数平方根sqrt(x),求余函数mod(x,y)

ceil(x):返回不小于x的最小整数值(天花板)

floor(x):返回不大于x的最大整数值,返回值转化为一个bigint(地板)

eg:1-100十个数一组,用ceil是1-10组,用floor是0-9组,一共10组。

select i,i/10,ceil(i/10) from test t;
2.随机数

dbms_random.random和dbms_random.random(x,y)
eg:使用DBMS_RANDOM.RANDOM产生随机数

select dbms_random.random,dbms_random.random from dual;

eg:使用DBMS_RANDOM.VALUE(x,y)函数1-20之间随机数

select dbms_random.value(1,20),dbms_random.value(1,20) from dual;
3.四舍五入

1).round(x)返回最接近参数x的整数,对其进行四舍五入
round(x,y)返回最接近于参数x的数,其值保留到小数点后面y位,若y为负值,则对小数点左边y位进行四舍五入。
2).trunc(X,Y)返回被舍去志小数点后Y位的数字X。若Y 的值为0,则结果不带小数点或不带小数部分,若Y 设为负数,则截取(归零)X小数点左起第Y位开时后面所有地位的值。
round函数在截取值时会四舍五入,而trunc(x,y)直接截取值,并不进行四舍五入。

4.符号函数sign(x)

sign(x)返回参数的符号,x的值为负、零或正时返回结果依次为-1、0或1。

5.幂运算函数power和exp

因为工作中用到的不是太多,所以在这里就不多做介绍了。

二、字符串函数

1. 计算字符串长度

length函数计算的是字符串的长度,而lengthb函数计算的是字符串的字节数。
eg:

select length('长安 zlabcd') from dual;

上面语句的结果为8。

2.合并字符串函数

concat(s1,s2),也可以使用“|”关联
eg:

seelct concat('中 连','zlsoft') from dual;
3.字符串搜索函数instr(s,x)

eg:

select instr('hello zlsoft','f') from dual;

答案:11

4.获取指定的字符串substr(s,m,n)

其中参数s代表字符串,m代表截取的位置,n代表截取长度。m为正数,代表是从左往右的第m位开始截取;m为负数,代表截取长度从右往左的第n位开始,m为0与m为1等效。若要截取的字符串中含有空格,空格也要算在内。无论m的正负,截取的顺序都是从左往右的。
eg:

---m为正数
select substr('zlsoft',2,3) from dual;---lso
---m为负数
select substr('zlsoft',-2,1) from dual;---ft
select substr('zlsoft',-2,3) from dual;---ft
---m为0
select substr('zlsoft',0,4) from dual;---zlso

m为负数时,当|m|≤n,截取的长度取|m|;当|m|≥n,截取长度取n。

5.替换字符串函数replace(s1,s2,s3)

若没有写s3的值是将s1与s2相同的值变成空。

6.大小写转换函数

lower(str)和upper(str)是将字符串str的字母全部变成小/大写。

initcap(str)是将字符串str的首字母变成大写。

7.ltrim()和rtrim()

ltrim(s,n)函数将删除指定的左侧字符,其中s是目标字符串,n是需要查找的字符。如果n不指定,则表示删除左侧的空格。n不指定的方式,可用于左对齐。

rtrim(s,n)函数将删除指定的右侧字符,其中s是目标字符串,n是需要查找的字符,如果n不指定,则删除右侧的空格。n不指定的方式,可用于右对齐。

---ltrim
select ltrim('aaazlsoftbbb','a') from dual;---zlsoftbbb
select ltrim('    zlsoft') from dual;---zlsoft(rtrim同理)
---rtirm
select rtrim('aaazlsoftbbb','b') from dual;---aaazlsoft
8.删除指定字符串函数trim()

trim函数将删除指定的前缀或者后缀的字符,默认删除空格,语法格式如下:

trim(leading|trailing|both string1 from string2)

其中,leading删除string1的前缀字符;both删除string1的前缀和后缀字符;trailing删除string1的后缀字符;string1表示删除的指定字符,默认删除空格,string2代表被操作的源字符串。
eg:

select trim(both 't' from 'this is zlsoft'),
       trim(leading 't' from 'this is zlsoft'),
       trim(trailing 't' from 'this is zlsoft'),
       trim('  this is zlsoft')
  from dual;

答案:his is zlsof;his is zlsoft;this is zlsof;this is zlsoft;

9.填充函数lpad()和rpad()

lpad函数将左边的字符串填充一些特定的字符其语法格式如下:

lpad(string,n,[pad_string])

string代表字符或者参数,n为字符的长度,是返回的字符串的数量,pad_string代表填充的字符。
eg:

---lpad
select lpad('12345',10,'*') from dual;---*****12345
---rpad
select rpad('12345',10,'*') from dual;---12345*****
10.chr()函数

该函数返回与所给数值等当的字符,返回的字符取决于数据库所依赖的字符集。
常用:chr(32)表示空格,chr(39)表示单引号,chr(10)表示回车

11.translate()函数

这一函数有三个参数,目标字符串、源字符串和目的字符串。在目标字符串与源字符串中均出现的字符,将会被替换成对应的字符串的字符(注意字符替换 位置的对应关系)。
eg:

select translate('13579B','0123456789AB','AZSLDSFOGFHT') from dual;---zlsoft
12.日期和时间函数

1).获取当前日期和时间的函数sysdate()

select sysdate from dual;

2).使用日期函数获取指定格式的系统当前时间,如下:

select to_char(sysdate,'YYYY-MM-DD') from dual;

3).systemstamp函数获取当前系统时间,该时间包括时区信息,精确到微妙,使用systemstamp()函数获取系统当前时间,sql如下:

select systemstamp from dual;

4.获取指定月份的最后一天的函数last_day(date),sql如下:

select last_day(sysdate) from dual;

5).获取指定日期后一周的日期函数

next_day(date,char)函数获取当前日期向后的一周对应日期,char表示是星期几,全称和缩写都允许,但必须是有效值。

select next_day(sysdate,'星期日') from dual;

6).获取指定日期特定部分的函数

extract(datetime)函数可以从指定的时间中提取特定的部分,例如年份、月份或时等。

select extract(year from sysdate),extract(hour from timestamp '2020-8-13 15:22:12') from dual;

7).获取两个日期之间的月份数

months_between(data1,date2)函数返回date1和date2之间的月份数,返回负数代表第一个日期在前,第二个日期在后。

select months_between(to_date('2020-08-08','yyyy-mm-dd'),to_date('2020-01-08','yyyy-mm-dd')) one from dual;---7

8).add_months函数

add_months函数可以给指定的时间加上计划的时间,例如给指定的日期增加一个月、一天等

eg:给原定时间(‘2020-08-11’)增加1个月变为修改后时间(‘2020-9-11’)

select to_date('2020-8-11','yyyy-mm-dd') 原定时间,add_months(to_date('2020-8-11','yyyy-mm-dd'),1) 修改后时间 from dual;
13.数值转换为字符串函数to_char()

to_char函数将一个数值参数转换为字符型数据,语法格式:to_cahr(n,[fmt[nlsparam]]),其中参数n代表数值型数据,参数fmt代表要转换成字符的格式。nlsparam参数代表指定fmt的特征,包括小数点字符、组分隔号或钱币符号。其中,例5.44中第二个to_char转换的是24小时制。

eg:

select to_char(10.12345,'99.999') from dual;---10.123
select to_char(sysdate,'YYYY-MM-DD'),to_char(sysdate,'HH24:MI:SS') from dual;

答案:2021-01-17 21:57:00

select to_char(0.12345) from dual;

上面的sql语句的答案是.12345

要想显示0.12345,方法如下:

select to_char(0.12345,'0.00000') from dual;
14.字符转换日期

to_date函数将一个字符型数据转换为日期数据,语法格式:

to_date(n,[fnt[nlsparam]])

其中参数char代表需要转换的字符串。参数ftm代表要转换成字符的格式。
nlsparam参数控制格式化使用的语言类型,包括小数点、组分隔号或钱币符号。

select to_char(to_date('2020-08-11','YYYY-MM-DD'),'MONTH') from dual;---8月
15.字符串转数字函数

to_number函数将一个字符型数据装换成数字数据,语法格式:
to_number(expr[,fmt[,nlsparam]]),其中参数expr代表需要转换的字符,参数ftm代表要转换数字的格式。nlsparam参数指定ftm的特征,包括小数点字符、组分隔号或钱币符号。

select to_number('2020.0811','9999.9999') from dual;---2020.0811
16.系统信息函数

1).user函数返回当前会话的登录名

eg:使用user函数返回当前会话的登录名称

select user from dual;

2).返回会话及上下文信息函数
userenv返回当前会话的信息,语法格式:

userenv(parameter)

eg:使用userenv函数返回当前会话的对应语言和字符集信息

select 	userenv('language') from dual;
17.聚合函数

聚合函数主要用在日常数据和日期的聚合及各种数据处理上。

count(),sum(),avg(),max(),min()

这里就不一一介绍了。

18.其他函数(nvl,decode)

主要是nvl函数和decode函数

1).nvl函数的功能是实现空值的转换,根据第一个表达式的值是否为空来返回响应的列名或表达式,主要用于对数据列上的空值进行处理,语法格式:

nvl(string1,replace with)

如果第一个参数的值为空格,则返回第二个参数的值,否则返回第一个参数的值。如果参数的值为空值,则返回空值。第一个参数和第二个参数可以是任意类型的数据,但两个参数的数据类型必须相同(或能够由oracle隐式转换为相同的类型)。
2).decode函数

decode(AA,V1,R1,V2,R2)
解释:
IF AA=V1 THEN RETURN R1
IF AA=V2 THEN RETURN R2
...
ELSE
RETURN NULL
19.oracle中的rownum机制原理及用法解释

1).概述

rownum是oracle引入的虚列。在物理上这个虚列并不存在,只是在查询是才构造出来。伪列通常是自由分配的,用户无法修改等操作。

2).特点

rownum不属于任何表

rownum存在的前提,先有结果表

rownum总是从1开始

使用rownum进行分页查询需要把rownum转化为实列,并针对rownum查询。

使用rownum时,只支持<、<=和!=符号,不支持>,>=,=和between…and符号。

eg:

select rat.* from
(
  select t2.*,rownum r2 from
  (
      select t.*,rownum r1 from test_ljb t order by nvl(salary,0) desc
      --这里需要说明的是,rownum仅仅对的结果集动态标记,而排序并不会生成新的结果集。
      --所以这条语句的rownum看起来并不是按照1-10的顺序排列。
      --事实上,这里的rownum r1并不会用到,为了看起来更加直观,加上的。
   ) t2
) rst
where rst.t2 between 4 and 6

3).如果rownum和order by在用一个查询中,那么会由order by子句中重新排序。

20.总结例题(例题中会包括存储过程等知识)
第一题

postgresql timestamp转换成string_函数返回


1).删除重复的

delete emp where not in (select min(rowid) from emp group by 员工编号);

2).写一条语句,按照姓名字段降序查询出第3到第7条的数据

注:oracle中有limit函数,但是用法与mysql中用法不一样。

select * from
(select rownum 序号,a.* from
(select t.* from emp t order by t.姓名 desc) a) a
where 序号 between 3 and 7;

3)

postgresql timestamp转换成string_oracle_02

select substr(a.员工编号,1,1) 员工编号头位,
sum(a.工资+a.奖金) 总收入,
sum(decode(a.员工类型,'正式',a.工资+a.奖金)) 正式员工收入,
sum(decode(a.员工类型,'使用',a.工资+a.奖金)) 使用员工收入,
round(avg(a.工资+a.奖金),2) 平均收入,
decode(sign(avg(a.工资+a.奖金)-3000),1,'3000以上',-1,'3000以下') 平均收入水平,
from emp a
group by substr(a.员工编号,1,1)
having sum(a.工资+a.奖金) > 5000;

4).写一条查询语句,按照名字字段降序查询出第3到第7条的数据。

select * from(select t.*,rownum rw from emp_test t order by t.姓名 desc) where rw<8 and rw<2;

提示:字段中带有()的,要使用双引号。

删除重复的数据(此题的数据不是上面的表,读者可以当不存在,主要是方便本人记录)

delete from doctor_test d
 where d.id in
       (select d.id from doctor_test group by d.id having count(d.id) > 1)
   and rowid not in (select min(rowid)
                       from doctor_test d
                      group by d.id
                     having count(d.id) > 1);
第二题

postgresql timestamp转换成string_数据_03


postgresql timestamp转换成string_字符串_04

select c.id, c.姓名, c.职称, c.所属科室, e.所属科室上级科室
  from (select r.id, r.姓名, r.职称, k.科室名 所属科室
          from 人员表 r, 科室表 k, 科室人员 t
         where k.id = t.科室id
           and r.id = t.人员id) c,
       (select a.科室名, d.科室名 所属科室上级科室
          from 科室表 a, 科室表 d
         where a.上级id = d.id) e
 where c.所属科室 = e.科室名
 order by c.id;
第三题

postgresql timestamp转换成string_oracle_05


相关数据

CREATE TABLE DEPT      
(
DEPTNO NUMBER(2) CONSTRAINT PK_DEPT PRIMARY KEY,      DNAME VARCHAR2(14) ,      LOC VARCHAR2(13)
 ) ; 

INSERT INTO DEPT VALUES      (10,'ACCOUNTING','NEW YORK'); 
INSERT INTO DEPT VALUES (20,'RESEARCH','DALLAS');  
INSERT INTO DEPT VALUES      (30,'SALES','CHICAGO');  
INSERT INTO DEPT VALUES      (40,'OPERATIONS','BOSTON');  



CREATE TABLE EMP      
(
EMPNO NUMBER(4) CONSTRAINT PK_EMP PRIMARY KEY,      ENAME VARCHAR2(10),      JOB VARCHAR2(9),      MGR NUMBER(4),      HIREDATE DATE,      SAL NUMBER(7,2),      COMM NUMBER(7,2),      DEPTNO NUMBER(2) CONSTRAINT FK_DEPTNO REFERENCES DEPT
);    
INSERT INTO EMP VALUES     (7369,'SMITH','CLERK',7902,to_date('17-12-1980','dd-mm-yyyy'),800,NULL,20); 
INSERT INTO EMP VALUES     (7499,'ALLEN','SALESMAN',7698,to_date('20-2-1981','dd-mm-yyyy'),1600,300,30); 
INSERT INTO EMP VALUES     (7521,'WARD','SALESMAN',7698,to_date('22-2-1981','dd-mm-yyyy'),1250,500,30);  
INSERT INTO EMP VALUES    (7566,'JONES','MANAGER',7839,to_date('2-4-1981','dd-mm-yyyy'),2975,NULL,20); 
INSERT INTO EMP VALUES    (7654,'MARTIN','SALESMAN',7698,to_date('28-9-1981','dd-mm-yyyy'),1250,1400,30); 
INSERT INTO EMP VALUES    (7698,'BLAKE','MANAGER',7839,to_date('1-5-1981','dd-mm-yyyy'),2850,NULL,30); 
INSERT INTO EMP VALUES    (7782,'CLARK','MANAGER',7839,to_date('9-6-1981','dd-mm-yyyy'),2450,NULL,10); 
INSERT INTO EMP VALUES    (7788,'SCOTT','ANALYST',7566,to_date('13-7-87','dd-mm-rr')-85,3000,NULL,20); 
INSERT INTO EMP VALUES    (7839,'KING','PRESIDENT',NULL,to_date('17-11-1981','dd-mm-yyyy'),5000,NULL,10);  
INSERT INTO EMP VALUES    (7844,'TURNER','SALESMAN',7698,to_date('8-9-1981','dd-mm-yyyy'),1500,0,30); 
INSERT INTO EMP VALUES    (7876,'ADAMS','CLERK',7788,to_date('13-7-87', 'dd-mm-rr')-51,1100,NULL,20);  
INSERT INTO EMP VALUES    (7900,'JAMES','CLERK',7698,to_date('3-12-1981','dd-mm-yyyy'),950,NULL,30); 
INSERT INTO EMP VALUES    (7902,'FORD','ANALYST',7566,to_date('3-12-1981','dd-mm-yyyy'),3000,NULL,20);  
INSERT INTO EMP VALUES    (7934,'MILLER','CLERK',7782,to_date('23-1-1982','dd-mm-yyyy'),1300,NULL,10);  


CREATE TABLE BONUS      
(
      ENAME VARCHAR2(10)  ,      JOB VARCHAR2(9)  ,      SAL NUMBER,      COMM NUMBER      
) ;      
CREATE TABLE SALGRADE      ( GRADE NUMBER,      LOSAL NUMBER,      HISAL NUMBER );
INSERT INTO SALGRADE VALUES (1,700,1200);  
INSERT INTO SALGRADE VALUES (2,1201,1400); 
INSERT INTO SALGRADE VALUES (3,1401,2000);  
INSERT INTO SALGRADE VALUES (4,2001,3000); 
INSERT INTO SALGRADE VALUES (5,3001,9999);  
COMMIT;

第一部分
1).

select e.job from emp e where e.sal>2000 group by e.job ;select e.job from emp e where e.sal>2000 group by e.job ;

2).

select e.empno, e.ename, e.job, e.mgr, e.hiredate, e.sal, e.comm, e.deptno
  from emp e
 where e.sal > (select emp.sal from emp where emp.ename = 'ALLEN');

3).

select e.ename 名字, (e.sal + nvl(e.comm,0)) 收入, e.sal 工资, e.comm 奖金
  from emp e
 where (e.sal + nvl(e.comm,0)) not between 1000 and 2000
 order by (e.sal + nvl(e.comm,0)) desc;

4).

select e.ename name员工姓名,
       e.job,
       t.ename mgr_name上级姓名,
       t.sal mgr_sal上级工资
  from emp e left join emp t on e.mgr = t.empno;

第二部分
1).

alter table emp add sal_rank number(2) null;

create sequence sq_test
increment by 1
start with 1
maxvalue 14
minvalue 1
nocycle
nocache;

update (select e.sal_rank from emp e order by e.sal) a
   set a.sal_rank = sq_test.nextval;

select e.* from emp e order by e.sal;

2).

select a.*
  from (select t.*, rownum rn
          from (select e.* from emp e order by e.sal_rank desc) t) a
 where a.rn between 3 and 5;

3).

declare 
 cursor cursor_工号姓名工资
 is select e.empno,e.ename,e.sal from emp e where e.job='CLERK';
 reocrd_工号姓名工资 cursor_工号姓名工资%rowtype;
begin
  open cursor_工号姓名工资;
  loop
    exit when cursor_工号姓名工资%notfound;
    fetch cursor_工号姓名工资 into reocrd_工号姓名工资;
    dbms_output.put_line(reocrd_工号姓名工资.empno||'-'||reocrd_工号姓名工资.ename||'-'||reocrd_工号姓名工资.sal);
    end loop;
    close cursor_工号姓名工资;
    end;
第三题
  1. 请仔细思考,并完成如下要求:(20分)
    1) 建立一张名为test_收费项目的表(共三个字段ID(number)、收费科室(varchar2 100)、收费项目(varchar2 (100))
    2) 写一个匿名块,插入30条数据,具体数据要求如下:(提示,可以使用循环以及if语句)
    ID(number) 收费科室(varchar2 100) 收费项目(varchar2 100)
    1 内科1 内科收费项目1
    2 内科2 内科收费项目2
    3 内科3 内科收费项目3
    4 内科4 内科收费项目4
    5 内科5 内科收费项目5
    6 内科6 内科收费项目6
    7 内科7 内科收费项目7
    8 内科8 内科收费项目8
    9 内科9 内科收费项目9
    10 内科10 内科收费项目10
    11 外科1 外科收费项目1
    12 外科2 外科收费项目2
    13 外科3 外科收费项目3
    14 外科4 外科收费项目4
    15 外科5 外科收费项目5
    16 外科6 外科收费项目6
    17 外科7 外科收费项目7
    18 外科8 外科收费项目8
    19 外科9 外科收费项目9
    20 外科10 外科收费项目10
    21 儿科1 儿科收费项目1
    22 儿科2 儿科收费项目2
    23 儿科3 儿科收费项目3
    24 儿科4 儿科收费项目4
    25 儿科5 儿科收费项目5
    26 儿科6 儿科收费项目6
    27 儿科7 儿科收费项目7
    28 儿科8 儿科收费项目8
    29 儿科9 儿科收费项目9
    30 儿科10 儿科收费项目10
    3)对该表增加一列,收费项目价格(number(10)),并更新数据(内科收费项目统一为10,外科收费项目统一为200,儿科收费项目统一为30)

1).

create table test_收费项目表
(
ID number(3),
收费科室 varchar2(100),
收费项目 varchar2(100)
);

2).

declare
 i int:=1;
 m constant int:=10;
begin
  for i in 1..m loop
    insert into test_收费项目表(ID,收费科室,收费项目) values (i,'内科'||(i),'内科收费项目'||(i));
end loop;
    for i in 1..m loop
    insert into test_收费项目表(ID,收费科室,收费项目) values ((i+10),'外科'||(i),'外科收费项目'||(i));
end loop;
for i in 1..m loop
    insert into test_收费项目表(ID,收费科室,收费项目) values ((i+20),'儿科'||(i),'儿科收费项目'||(i));
end loop;
        end;

3).

declare
a int:=1;
b int:=11;
c int:=21;
i int:=10;
j int:=20;
l int:=30;
begin
  for a in 1..i loop
    update TEST_收费项目表 t set t.收费项目价格=10 where t.id between 1 and 10;
  end loop;
  for b in 11..j loop
    update TEST_收费项目表 t set t.收费项目价格=20 where t.id between 11 and 20;
  end loop;
  for b in 21..l loop 
    update TEST_收费项目表 t set t.收费项目价格=30 where t.id between 21 and 30;
  end loop;
end;
第四题

4.按脚本建表( ),并完成下述要求(20分)
1)删除表中重复的数据。(提示:使用rowid)
2)对考核成绩80分(含80分)以上医生的奖金增加500元,对考核成绩在70分(含70分)以下的医生减少奖金300元。(提示:使用update操作)
3)完成1)和2)之后,写一条SQL,按ID的首位分组查询出:
ID首位
平均收入
收入的总和(收入=工资+奖金)
分组收入总和在5000以上的数据
同时判断收入水平是否在5000以上

4)建立一个含传入参数(v_姓名)的存储过程,调用该过程可以对输入相应姓名的医生的考核成绩(mark)加2分。
数据:

create table doctor_test(ID varchar2(10),姓名 varchar2(10),工资 number(10),奖金 number(10),性别 varchar2(10),分数 varchar2(10));

insert into doctor_test values('A01' , '赵雷' , 4000 ,1100,'男',64);
insert into doctor_test values('A02' , '钱电' , 4100 ,1300,'男',70);
insert into doctor_test values('A02' , '钱电' , 4100 ,1300,'男',70);
insert into doctor_test values('A03' , '孙风' , 4200 ,1200,'男',70);
insert into doctor_test values('A04' , '李云' , 4600 ,1400,'男',84);
insert into doctor_test values('B01' , '周梅' , 4100 ,1100,'女',90);
insert into doctor_test values('B01' , '周梅' , 4100 ,1100,'女',90);
insert into doctor_test values('B02' , '吴兰' , 4200 ,1100,'女',84);
insert into doctor_test values('B03' , '郑竹' , 4700 ,1600,'女',86);
insert into doctor_test values('B03' , '郑竹' , 4700 ,1600,'女',86);
insert into doctor_test values('B04' , '张书' , 4200 ,1000,'女',87);
insert into doctor_test values('B05' , '李虎' , 4300 ,800,'女',88);
insert into doctor_test values('C01' , '王龙' , 4100 ,200,'女',60);
insert into doctor_test values('C01' , '王龙' , 4100 ,200,'女',60);
insert into doctor_test values('C02' , '赵雨' , 4200 ,500,'女',64);
insert into doctor_test values('C03' , '孙明' , 4100 ,800,'女',40);

1).

delete from doctor_test d
 where d.id in
       (select d.id from doctor_test d group by d.id having count(d.id) > 1)
   and rowid not in (select min(rowid)
                       from doctor_test d
                      group by d.id
                     having count(d.id) > 1);

2).

update doctor_test d
   set d.奖金 =d.奖金+500
       where d.id in (select d.id from doctor_test d where d.分数 >= 80);
update doctor_test d
   set d.奖金 =d.奖金-300
       where d.id in (select d.id from doctor_test d where d.分数 <=70);

3).

select substr(d.id,1,1) ID首位,
       sum(d.工资+d.奖金) 总收入,
       round(avg(d.工资+d.奖金),2) 员工平均收入,
       (case when round(avg(d.工资+d.奖金),2)>5000 then '5000以上'
       when round(avg(d.工资+d.奖金),2)<5000 then '5000以下'
       end) 平均收入水平
from doctor_test d group by substr(d.id,1,1) having sum(d.工资+d.奖金)>5000;

4).

create or replace procedure v_doctor(v_姓名 in varchar2)
as 
cur_分数 doctor_test.分数%type;
begin
  select d.分数+2 into cur_分数 from doctor_test d where d.姓名=v_姓名;
  dbms_output.put_line('分数:'||cur_分数);
  end;
begin
  v_doctor('李云');
  end;