欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Oracle函数、子程序实例讲解

程序员文章站 2022-06-14 12:19:08
子程序 一、子程序概述 pl/sql命名程序块的定义在pl/sql程序块的声明部分,用户称之为子程序。 通俗讲:命名的 pl/sql 块,编译并存储在中。 子程序构成: l 声明部分 l 可执行部分...

子程序

一、子程序概述

pl/sql命名程序块的定义在pl/sql程序块的声明部分,用户称之为子程序。

通俗讲:命名的 pl/sql 块,编译并存储在中。

子程序构成:

l 声明部分

l 可执行部分

l 异常处理部分(可选)

子程序的优点:

模块性:子程序可以将程序划分成易于管理,定义明确的逻辑模块,它支持自顶向下的设计方法。

可维护性:简化维护操作。

可重性:子程序一旦被定义可以用于许多个应用程序。

安全性:通过设置权限,使数据更安全。

二、子程分类

oracle提供了4种类型的子程序:存储过程、函数、包、触发器。

过程 - 执行某些操作

函数 - 执行操作并返回值

三、子程序之:函数

函数是可以返回值的命名的 pl/sql 子程序。

函数分为:内置函数 和 自定义函数。

1. 内置函数

由oracle提供的一系列用于执行特定操作的函数。

sql内置函数带有一个或多个参数并返回一个值。

sql内置函数分为:单行函数、分组函数、分析函数

l 单行函数:从表中查询的每一行只返回一个值。

日期函数,数字函数,字符函数,转换函数,其他函数

l 分组函数:基于一组行来返回结果。为每一组行返回一个值。

count()、sum()、avg()、max()、min()

l 分析函数:根据一组行来计算聚合值。用于计算完成聚集的累计排名、移动平均数等。

分析函数为每组记录返回多个行。

row_number、rank、dense_rank

1.1 数值函数

round() 四舍五入

select round( 10054.345 ) from dual;

--返回:10054

select round( 10054.345 , 2 ) from dual;

--返回:10054.35 精确到小数点后2位

select round( 10054.345 , -2 ) from dual;

--返回:10100

trunc() 取整(无四舍五入)

select trunc( 45.67 ) from dual;

--返回:45

select trunc( -45.22 , 0 ) from dual;

--返回:-45

floor() 取整(最小值,无四舍五入)

select floor( 45.67 ) from dual;

--返回:45 最小的整数

select floor(-45.17) from dual;

--返回:-46 最小的负整数

mod() 求模(与java中的%一样)

select mod( 11 , 7) from dual;

--返回:4

power() 开方

select power( 5 , 2 ) from dual;

--返回:25 求5的2次方

sqrt() 开根号

select sqrt( 4 ) from dual;

--返回:2

sign()判断值的正负数

--正数返回1,0返回0,负数返回-1(以后常用)

select sign( 10 ) from dual;

--返回:1

1.2 字符函数

substr() 字符串截取

select substr( 'abcdefg' , 2 , 4 ) from dual;

--返回:bcde 从第2位开始连续截取4个

--注意:sql和oracle中字符串角标是从1开始;而java中字符串角标是从0开始。

length() 求字符串长度(字符个数,与中英文所占字节无关)

select length( 'abc' ) from dual;

--返回:3

instr() 查找字符位置(类似于java中的charindex,sql server中的indexof)

select instr( 'abcadefag' , 'a' ) from dual;

--返回:1 默认从字符串角标1开始查找

select instr( 'abcsadefag' , 'a' , 4 ) from dual;

--返回:5 从字符串角标4开始查找

concat() 连接 与||相同

select concat('a','b') from dual;

--结果:ab

replace() 替换

select replace('abcdefg','a',9) from dual;

--结果:9bcdefg

select translate('adbecf','abc','123') from dual;

lpad() 左填充

select lpad('abc',10,'6') from dual; --10是字符串总长度

--结果:6666666abc

rpad() 右填充

select rpad('abc',10,'6') from dual;

--结果:abc6666666

trim()

--有两个意思:去除字符串两边的空格

-- 去除字符串两边指定的字符

--语法:trim('字符1' from '字符串2')

select trim('a' from 'aabbbccdda') from dual;

--结果:bbbccdd

chr() ascii码对应的字符

select chr(97) from dual;

--结果:a

ascii() 字符对应的ascii码

select ascii('a') from dual;

--结果:97

decode()

--decode(value,if1,then1,if2,then2,if3,then3,...,else)

表示如果value 等于if1时,decode函数的结果返回then1,...,如果不等于任何一个if值,则返回else。初看一下,decode()只能做等于测试,但刚才也看到了,我们通过一些函数或计算替代value,是可以使decode()函数具备大于、小于或等于功能。

select decode('a','a',1,'b',2,'c',3) from dual;

--1

--工资大于3500提示交税,等于3500刚刚好,小于3500要努力

--分析:三种情况

select decode(sign(sal-3500),1,'交税',0,'刚好',-1,'努力') from emp;

1.3 日期函数

sysdate 取当前时间

select sysdate from dual;

--显示时间类型(date),但要转成字符串呢?

systimestamp 获取系统当前时间

select systimestamp from dual;

--结果比较长,格式是格林乔治时间

add_months() 取月份实现加月份

select add_months(sysdate,3) from dual;

--在当前系统时间月份上加3

select add_months(to_date('2015-12-12','yyyy-mm-dd'),3) from dual;

--在2015-12-12的月份上加3

extract() 取(年月日)

select extract(day from sysdate) from dual;

--取当前系统的日

select extract(month from sysdate) from dual;

--取当前系统的月

--案例:求每个月的入职人数

按月分组统计

select extract(month from hiredate),count(*) from emp

group by extract(month from hiredate)

--求每年每个月的入职人数

select extract(year from hiredate),extract(month from hiredate),count(*) from emp

group by extract(year from hiredate),extract(month from hiredate)

months_between() 时间差

select months_between(sysdate,to_date('2015-12-12','yyyy-mm-dd')) from dual;

--前面的日期减去后面的日期,返回是月份,会出现负数,也会出现小数(最精确的)

last_day() 取本月的最后一天

select last_day(sysdate) from dual;

--2016/2/29 16:59:13 本月最后一天的当前时间

next_day() 下一个日期

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

--结果:下一个“星期四”的日期

问:下一周的星期三和下一个星期三是一样的吗?

round() 取最近的一天

--取整,超过12点算第二天,有四舍五入功能

select round(to_date('2009-09-08 12:12:12','yyyy-mm-dd hh:mi:ss')) from dual;

--只取整数部分 2009/9/9 还有超过12点就算9号了

select round(to_date('2009-09-08 12:12:12','yyyy-mm-dd hh24:mi:ss')) from dual;

--只取整数部分 2009/9/9

trunc() 截取日期函数

--取整,当天

select trunc(to_date('2009-09-08 12:12:12','yyyy-mm-dd hh:mi:ss')) from dual;

--只取整数部分 2009/9/8

select trunc(to_date('2009-09-08 23:12:12','yyyy-mm-dd hh24:mi:ss')) from dual;

--只取整数部分 2009/9/8

1.4 转换函数

转换函数将值从一种数据类型转换为另一种数据类型。

to_char

将非char类型转成char类型

select to_char(sysdate,'yyyy-mm-dd') from dual;

select to_char(sysdate,'yyyymmdd') from dual;

select to_char(sysdate,'yyyy"年"mm"月"dd"日"') from dual;

--这是oracle中唯一用到双引号的地方

to_date

将非date类型转成date类型

select to_date('2016-09-09','yyyy-mm-dd') from dual;

select to_date('2016-09-09 18:20:30','yyyy-mm-dd hh24:mi:ss') from dual;

to_number

将非数值型转成数值型

select to_number('345') from dual;

select to_number('34a5') from dual;

1.5 集合函数

count()

sum()

avg()

max()

min()

1.6 其他函数

转换空值函数

nvl(exp1,exp2)

--如果oracle第一个参数为空那么显示第二个参数的值,如果第一个参数的值不为空,则显示第一个参数本来的值。

select ename,nvl(comm, -1) from emp;

nvl2(exp1,exp2,exp3)

--如果该函数的第一个参数为空那么显示第三个参数的值,如果第一个参数的值不为空,则显示第二个参数的值。

select ename,nvl2(comm,-1,1) from emp;

nullif(exp1,exp2)

--如果exp1和exp2相等则返回空(null),否则返回第一个值。

select ename,nullif(comm,-1) from emp;

1.7 分析函数

7. 分析函数

主查询结果的基础上进行一定的分析,如分部门汇总,分部门求均值等等。

(1)oracle 分析函数建立在所谓的数据窗口之上,数据窗口可以理解为一个数据集合。

主查询的数据可以按照不同的标准分割成不同的数据集。

比如partition by manager_id,按照manager_id将主查询的数据分成n(n代表有多少个不同的manager_id)个不同的数据窗口。

(2)其次,数据窗口内部还应该与一定的顺序通过 order by 实现

row_number() over()

rank() over()

dense_rank() over()

分析函数和group by的区别和联系:

(1)分析函数的功能大部分都可以通过group by 来聚合完成

(2)分析函数查询出来的行数是由主查询决定的,group by 的行数结果是由group by 后面的集合构成的唯一性组合决定的,通常比主查询的结果行数少。

sum(emp.salary) over(partition by emp.manager_id) sum_salary_department, --该部门薪水总额

dense_rank() over(partition by emp.manager_id order by emp.salary desc) rank_salary_dept, --该人员的部门薪水排行

min(emp.salary) keep(dense_rank first order by emp.salary) over(partition by emp.manager_id) min_salary_dept_first, --部门的最低薪水

first_value(emp.salary) over(partition by emp.manager_id order by emp.salary) min_salary_dept_firstv, --部门的最低薪水

lag(emp.full_name, 1, '00') over (order by emp.salary desc) last_persion, --薪水在自己前一位的人

2. 自定义函数

2.1 创建函数(in、out、in out)

创建函数的语法:

create [or replace] function

[(param1,param2)]

return is|as

[local declarations]

begin

executable statements;

return result;

exception

exception handlers;

end;

--案例:给编号,返回工资'交税'还是'刚好',还是'努力'

create or replace function f_n126(sid number)

return varchar2

is

ssal number(8,2);

str varchar2(22); --注意,该处不用declare定义

begin

select sal into ssal from emp where empno=sid;

if ssal>3500 then

str:='交税';

elsif ssal=3500 then

str:='刚好';

else

str:='努力';

end if;

return str;

end;

create or replace function my_sum(n_a in number)

return number

is

n_sum number(5):=0;

begin

for int_s in 1..n_a loop

n_sum:=n_sum+int_s;

end loop;

return n_sum;

end;

定义函数的限制:

  函数只能接受 in 参数,而不能接受 in out 或 out 参数

  形参不能是 pl/sql 类型

  函数的返回类型也必须是数据库类型

访问函数的两种方式:

  使用 pl/sql 块

  使用 sql 语句

创建函数

create or replace function fun_hello

return varchar2

is

begin

return '朋友,您好';

end;

从 sql 语句调用函数:

select fun_hello from dual;

create or replace function

item_price_range (price number)

return varchar2 as

min_price number;

max_price number;

begin

select max(itemrate), min(itemrate)

into max_price, min_price

from itemfile;

if price >= min_price and price <= max_price

then

return '输入的单价介于最低价与最高价之间';

else

return '超出范围';

end if;

end;

declare

p number := 300;

msg varchar2(200);

begin

msg := item_price_range(300);

dbms_output.put_line(msg);

end;

2.2 调用函数

--oracle调用方式:

select f_n126(7369) from dual;

--pl/sql调用方式:

declare str varchar2(22);

begin

str:=f_n126(7369);

dbms_output.put_line(str);

end;

2.3 删除函数

drop function f_name;