文章目录
Oracle函数、Oracle单组函数、Oracle多行函数
1.函数基础
1.1SQL函数
注意:函数可以没有参数,但必须要有返回值。
1.2两种SQL函数
2.单行函数
2.1说明
单行函数:
- 操作数据对象
- 接收参数返回一个结果
- 只对一行进行变换
- 每行返回一个结果
- 可以转换数据类型
- 可以嵌套
- 参数可以是一列或一个值
语法:
function_name [(arg1, arg2,...)]
2.2字符函数
函数 | 描述 | 示例 | 结果 |
---|---|---|---|
lower | 全部转为小写 | lower(‘Hello World’) | hello world |
upper | 全部转为大写 | upper(‘Hello World’) | HELLO WORLD |
initcap | 首字母转为大写 | initcap(‘hello world’) | Hello World |
concat | 连接两个字符串 | concat(‘Hello’,‘World’) | HelloWorld |
substr | 在字符串str中从第m个位置开始取n个字符(位置从1开始) | substr(‘Hello World’,2,4) | ello |
length | 求长度 | length(‘Hello World’) | 11 |
instr | 从字符串strA中找出str所在的位置(返回第1个找到的,位置从1开始) | instr(‘Hello World!Hello’, ‘llo’) | 3 |
lpad | 把字符串str补齐到n个长度,不足就在左边加指定字符c; 如果str.length>n就取str的前n个字符 |
lpad(‘ith’, 5, ‘qq’) | qqith |
rpad | 把字符串str补齐到n个长度,不足就在右边加指定字符c; 如果str.length>n就取str的前n个字符(也是从前面取) |
rpad(‘ith’, 5, ‘qq’) | ithqq |
trim | 从字符串str的两端去掉字符(默认去掉空格) | trim(’ solang ') | solang |
replace | 将strA中的字符串strB替换为str | replace(‘asolaanga’, ‘a’, ‘’) | solng |
substr(str, startPosition, count)
如果第3个参数不指定(即不指定截取几个字符),就表示到最后。
lpad
与rpad
SQL> select lpad('smith', 3, '*') from dual;
LPA
---
smi
SQL> select rpad('smith', 3, '*') from dual;
RPA
---
smi
trim
将两端指定的字符去掉,使用方式特殊,注意:指定的字符只能指定一个。
SQL> select trim('a' from 'aabaslaabaa') from dual;
TRIM('A
-------
baslaab
2.2.1大小写控制函数
这类函数用于改变字符的大小写。
SQL> select * from emp where lower(ename) = 'smith';
2.2.2字符控制函数
2.3数字函数
函数 | 描述 | 示例 | 结果 |
---|---|---|---|
round | 四舍五入 | round(45.992, 2) | 45.99 |
trunc | 截断 | trunc(45.992, 1) | 45.9 |
mod | 求余 | mod(1600, 300) | 100 |
round
保留的位数可以指定正、零、负数。
SQL> select round(45.992, 2) from dual;
ROUND(45.992,2)
---------------
45.99
SQL> select round(45.992, 0) from dual;
ROUND(45.992,0)
---------------
46
SQL> select round(45.992, -1) from dual;
ROUND(45.992,-1)
----------------
50
SQL> select round(45.992, -2) from dual;
ROUND(45.992,-2)
----------------
0
trunc
舍掉后面的数,保留的位数可以指定正、零、负数。
SQL> select trunc(45.992, 1) from dual;
TRUNC(45.992,1)
---------------
45.9
SQL> select trunc(45.992, 0) from dual;
TRUNC(45.992,0)
---------------
45
SQL> select trunc(45.992, -1) from dual;
TRUNC(45.992,-1)
----------------
40
SQL> select trunc(45.992, -2) from dual;
TRUNC(45.992,-2)
----------------
0
mod
取余数
SQL> select mod(1600, 300) from dual;
MOD(1600,300)
-------------
100
SQL> select mod(16, 5) from dual;
MOD(16,5)
----------
1
SQL> select mod(15, 5) from dual;
MOD(15,5)
----------
0
2.4日期
MySQL中日期类型:date, time, datetime;Oracle中只有date。
Oracle中的日期型数据实际含有两个值: 日期和时间。函数SYSDATE
返回:日期和时间
默认的日期格式是DD-MON-RR
SQL> select sysdate-1 yesterday, sysdate today, sysdate+1 tomorrow from dual;
YESTERDAY TODAY TOMORROW
--------- --------- ---------
19-NOV-18 20-NOV-18 21-NOV-18
2.4.1日期的数学运算
在日期上加上或减去一个数字结果仍为日期。
两个日期相减返回日期之间相差的天数。
可以用数字除24来向日期中加上或减去小时。
SQL> select ename,(sysdate-hiredate) "day",(sysdate-hiredate)/7 "week", (sysdate-hiredate)/30 "month",(sysdate-hiredate)/365 "year" from emp;
当前时间,当前时间前一小时,当前时间前一分钟。
SQL> select sysdate,sysdate - 1/24,sysdate - 1/24/60 from dual;
2.4.2日期函数
默认的日期格式是DD-MON-RR
SQL> select sysdate from dual;
SYSDATE
---------
21-NOV-18
函数 | 描述 | 示例 | 结果 |
---|---|---|---|
months_between | 两个日期相差的月数 | months_between(sysdate, ‘21-SEP-2018’) | 2 |
add_months | 向指定日期中加上若干月数 | add_months(sysdate, -1) | 21-OCT-18 |
next_day | 指定日期的下一个日期 | next_day(sysdate, ‘THUR’) | 22-NOV-18 |
last_day | 本月的最后一天 | last_day(sysdate) | 30-NOV-18 |
round | 日期四舍五入 | round(sysdate, ‘month’) | 01-DEC-18 |
trunc | 日期截断 | trunc(sysdate, ‘month’) | 01-NOV-18 |
months_between
两个日期相差的月数
SQL> select months_between(sysdate, '21-SEP-2018') from dual;
MONTHS_BETWEEN(SYSDATE,'21-SEP-2018')
-------------------------------------
2
SQL> select months_between(sysdate, '21-DEC-2018') from dual;
MONTHS_BETWEEN(SYSDATE,'21-DEC-2018')
-------------------------------------
-1
SQL> select months_between(sysdate, '02-NOV-2018') from dual;
MONTHS_BETWEEN(SYSDATE,'02-NOV-2018')
-------------------------------------
.642333483
add_months
向指定日期中加上若干月数
SQL> select add_months(sysdate, 1) from dual;
ADD_MONTH
---------
21-DEC-18
SQL> select add_months(sysdate, -1) from dual;
ADD_MONTH
---------
21-OCT-18
next_day
从某个日期算起,下一个出现该星期几的日期
## 今天21号周三,下一个周四是明天
SQL> select next_day(sysdate, 'THUR') from dual;
NEXT_DAY(
---------
22-NOV-18
## 今天21号周三,下一个周三是28号
SQL> select next_day(sysdate, 'WED') from dual;
NEXT_DAY(
---------
28-NOV-18
last_day
本月的最后一天
SQL> select last_day(sysdate) from dual;
LAST_DAY(
---------
30-NOV-18
SQL> select last_day(sysdate-22) from dual;
LAST_DAY(
---------
31-OCT-18
round
日期四舍五入,四舍五入年表示月份在7月-12月的,会进位到年份的下一年1月1日,月份在1月-6月的表示当年1月1日;四舍五入月表示天份在16号及以后的天数,会进位到下一月1日,天份在1-15号表示当月1日;四舍五入日表示返回未来日期离给定日期最近的星期日,如果给定日期是星期日,那么四舍五入日返回给定日期。
SQL> select round(sysdate, 'year') from dual;
ROUND(SYS
---------
01-JAN-19
SQL> select round(sysdate, 'month') from dual;
ROUND(SYS
---------
01-DEC-18
SQL> select round(sysdate, 'day') from dual;
ROUND(SYS
---------
25-NOV-18
## 11月30号周五,未来最近的周日是12月2号
SQL> select round(sysdate + 9, 'day') from dual;
ROUND(SYS
---------
02-DEC-18
trunc
日期截断,截断年表示日期当年1月1日,截断月表示日期当月1号,截断日表示返回过去日期离给定日期最近的星期日,如果给定日期是星期日,那么截断日返回给定日期。
SQL> select trunc(sysdate, 'year') from dual;
TRUNC(SYS
---------
01-JAN-18
SQL> select trunc(sysdate, 'month') from dual;
TRUNC(SYS
---------
01-NOV-18
SQL> select trunc(sysdate, 'day') from dual;
TRUNC(SYS
---------
18-NOV-18
## 11月3号周六,过去最近的周日是10月28号
SQL> select trunc(sysdate - 18 , 'day') from dual;
TRUNC(SYS
---------
28-OCT-18
查找给定日期的第一天(就是几月1日)。
SQL> select last_day(add_months(sysdate, -1)) + 1 from dual;
LAST_DAY(
---------
01-NOV-18
SQL> select trunc(sysdate, 'month') from dual;
TRUNC(SYS
---------
01-NOV-18
2.5转换函数
隐式数据类型转换
Oracle自动完成下列转换:
显式数据类型转换
2.5.1TO_CHAR函数对日期的转换
语法:TO_CHAR(date, ‘format_model’)
格式:
必须包含在单引号中而且大小写敏感。此处大小写敏感不针对YYYY MM DD
等这种数字格式。
可以包含任意的有效的日期时间格式。
2.5.1.1日期格式的元素
格式 | 说明 | 举例 |
---|---|---|
YYYY | Full year in numbers(数字全年) | 2018 |
YEAR | Year spelled out(年的英文全称) | TWENTY EIGHTEEN |
MM | Two-digit value of month(两位数月份) | 11 |
MONTH | Full name of the month(月的全称) | NOVEMBER |
DY | Three-letter abbreviation of the day of the week(三字母缩写的星期几) | THU |
DAY | Full name of the day of the week(星期几全称) | THURSDAY |
DD | Numeric day of the month(数字天数) | 22 |
格式中首字母大写并且和首字母没有组成连续2个及以上大写字母,则显示结果中只有首字母大写;首字母大写并且和首字母组成连续两个大写字母,则全部显示大写。除格式全大写结果显示全部为大写,其它情况都是小写结果。
SQL> select to_char(sysdate, 'YYYY,yyyy,YYyy') from dual;
TO_CHAR(SYSDAT
--------------
2018,2018,2018
SQL> select to_char(sysdate, 'YEAR-year-Year-YEar-yeAR') from dual;
TO_CHAR(SYSDATE,'YEAR-YEAR-YEAR-YEAR-YEAR')
--------------------------------------------------------------------------------
TWENTY EIGHTEEN-twenty eighteen-Twenty Eighteen-TWENTY EIGHTEEN-twenty eighteen
SQL> select to_char(sysdate,'MONTH,month,Month,MOnth,MonTh') from dual;
TO_CHAR(SYSDATE,'MONTH,MONTH,MONTH,MONTH,MONTH')
--------------------------------------------------------------------------------
NOVEMBER ,november ,November ,NOVEMBER ,November
SQL> select to_char(sysdate,'DY,dy,Dy,dY') from dual;
TO_CHAR(SYSDATE,'DY,DY,DY,DY')
---------------------------------------------------
THU,thu,Thu,thu
SQL> select to_char(sysdate,'DAY,day,Day,DAy') from dual;
TO_CHAR(SYSDATE,'DAY,DAY,DAY,DAY')
--------------------------------------------------------------------------------
THURSDAY ,thursday ,Thursday ,THURSDAY
2.5.1.2时间格式的元素
除AM
,PM
大小写敏感外,其它数字格式对大小写不敏感。
格式 | 说明 | 举例 |
---|---|---|
HH | 12时制小时数 | 09 |
HH24 | 24时制小时数 | 21 |
MI | 分钟数 | 58 |
SS | 秒数 | 22 |
AM | 上午 | PM |
PM | 下午 | PM |
SQL> select to_char(sysdate,'HH24:MI:SS AM HH Pm') from dual;
TO_CHAR(SYSDATE,'
-----------------
21:58:22 PM 09 Pm
日期格式和时间格式可以任意组成有效的日期时间格式。
SQL> select to_char(sysdate,'yyyy-mm-dd hh:mi:ss') from dual;
TO_CHAR(SYSDATE,'YY
-------------------
2018-11-22 10:04:02
SQL> select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
TO_CHAR(SYSDATE,'YY
-------------------
2018-11-22 22:04:22
如果格式中有其它字符,需要使用双引号引起来。
SQL> select to_char(sysdate, 'yyyy"年"mm"月"dd"日" hh24"时"mi"分"ss"秒"') from dual;
TO_CHAR(SYSDATE,'YYYY"年"MM"月"DD
---------------------------------
2018年11月22日 22时14分33秒
2.5.2TO_CHAR函数对数字的转换
语法:TO_CHAR(number, ‘format_model’)
下面是在TO_CHAR函数中经常使用的几种格式:
本地货币符号不区分大小写,小写的l
也可以,不过尽量用大写,方便区分。
由于数据库编码使用AMERICAN_AMERICA.AL32UTF8
,所有本地货币符号为$
。
格式化位数不够时,返回格式化位数+1
长度的#。
0
补齐指定位数,.
小数点表示格式化小数点后的位数,,
千位符表示展示数字的格式。
货币符号
SQL> select lower(ename), to_char(sal, 'L999999') from emp where sal < 1250;
LOWER(ENAM TO_CHAR(SAL,'L999
---------- -----------------
smith $800
adams $1100
james $950
SQL> select lower(ename), to_char(sal, '$999999') from emp where sal < 1250;
LOWER(ENAM TO_CHAR(
---------- --------
smith $800
adams $1100
james $950
0
补齐指定位数
SQL> select lower(ename), to_char(sal, '$00000') from emp where sal < 1250;
LOWER(ENAM TO_CHAR
---------- -------
smith $00800
adams $01100
james $00950
## 格式化位数不够,返回格式化位数+1长度的#
SQL> select lower(ename), to_char(sal, '00') from emp where sal < 1250;
LOWER(ENAM TO_
---------- ---
smith ###
adams ###
james ###
SQL> select lower(ename), to_char(sal, '000') from emp where sal < 1250;
LOWER(ENAM TO_C
---------- ----
smith 800
adams ####
james 950
.
格式化小数点后的位数
SQL> select lower(ename), to_char(sal, '000.') from emp where sal < 1250;
LOWER(ENAM TO_CH
---------- -----
smith 800.
adams #####
james 950.
SQL> select lower(ename), to_char(sal, '0000.000') from emp where sal < 1250;
LOWER(ENAM TO_CHAR(S
---------- ---------
smith 0800.000
adams 1100.000
james 0950.000
,
千位符展示数字的格式
SQL> select lower(ename), to_char(sal, '999999') from emp where sal < 1250;
LOWER(ENAM TO_CHAR
---------- -------
smith 800
adams 1100
james 950
SQL> select lower(ename), to_char(sal, '$999,999.99') from emp where sal < 1250;
LOWER(ENAM TO_CHAR(SAL,
---------- ------------
smith $800.00
adams $1,100.00
james $950.00
SQL> select lower(ename), to_char(sal, '$999,99.0') from emp where sal < 1250;
LOWER(ENAM TO_CHAR(SA
---------- ----------
smith $8,00.0
adams $11,00.0
james $9,50.0
2.5.3TO_NUMBER和TO_DATE函数
2.5.3.1TO_NUMBER
语法:TO_NUMBER(str[, ‘format_model’])
将字符转换成数字。
'3'
已隐式转换为Number类型,再减去2。
SQL> select '3' - 2 from dual;
'3'-2
----------
1
SQL> select to_number('3','999') - 2 from dual;
TO_NUMBER('3','999')-2
----------------------
1
SQL> select to_number('$3','$999') - 2 from dual;
TO_NUMBER('$3','$999')-2
------------------------
1
带有货币符号的数字字符串显式转换为数字类型,再减去2。
2.5.3.2TO_DATE
语法:TO_DATE(str[, ‘format_model’])
将字符转换成日期。
SQL> select to_date('20181122', 'yyyymmdd') from dual;
TO_DATE('20181122'
------------------
22-NOV-18
2.6通用函数
这些函数适用于任何数据类型,同时也适用于空值
函数 | 描述 |
---|---|
NVL(expr1, expr2) | expr1为NULL,返回expr2;不为NULL,返回expr1 |
NVL2(expr1, expr2, expr3) | expr1不为NULL,返回expr2;为NULL,就返回expr3 (expr1 != null ? expr2 : expr3) |
NULLIF(expr1, expr2) | expr1和expr2相等返回NULL,不相等返回expr1 |
COALESCE(expr1, expr2, …,exprn) | COALESCE与NVL相比的优点在于COALESCE可以同时处理交替的多个值。 如果第一个表达式为空,则返回下一个表达式,对其他的参数进行COALESCE。 即:找第一个不为空的值。 |
SQL> select empno,ename,nvl(comm,0) from emp;
SQL> select empno,ename,nvl2(comm,sal+comm,sal) from emp;
SQL> select nullif('12','13'),nullif('12','12') from dual;
NU N
-- -
12
SQL> select empno,ename,coalesce(comm,null,90) from emp;
2.7条件表达式
在SQL语句中用于实现IF-THEN-ELSE逻辑。
使用两种方法:
CASE表达式:SQL99的语法,比较繁琐
DECODE函数:Oracle自己的语法,类似Java,比较简洁
2.7.1CASE表达式
根据员工的职位涨工资:总裁(PRESIDENT)1000、经理(MANAGER)800、其他400。
CASE
用法一:
select
empno,
lower(ename),
job,
sal 原来的工资,
(CASE job WHEN 'PRESIDENT' THEN sal+1000 WHEN 'MANAGER' THEN sal+800 ELSE sal+400 END) 涨后的工资
from
emp;
CASE
用法二:
select
empno,
lower(ename),
job,
sal 原来的工资,
(CASE WHEN job='PRESIDENT' THEN sal+1000 WHEN job='MANAGER' THEN sal+800 ELSE sal+400 END) 涨后的工资
from
emp;
2.7.2DECODE函数
decode(变量, 值1, 则a, 值2, 则b, … default)
select
empno,
lower(ename),
job,
sal 原来的工资,
(DECODE(job, 'PRESIDENT', sal + 1000,
'MANAGER', sal+800,
sal +400)
) 涨后的工资
from
emp;
default可以不写
select
empno,
lower(ename),
job,
sal 原来的工资,
(DECODE(job, 'PRESIDENT', sal + 1000,
'MANAGER', sal+800)
) 涨后的工资
from
emp;
2.8函数嵌套
单行函数可以嵌套。
嵌套函数的执行顺序是由内到外。
3.分组函数
3.1概念
分组函数作用于一组数据,并对一组数据返回一个值。
3.2语法
SELECT [column,] group function(column), ...
FROM table
[WHERE condition]
[GROUP BY group_by_expression]
[HAVING group_condition]
[ORDER BY column];
3.3类型
函数 | 描述 | |
---|---|---|
COUNT | 数量 | |
SUM | 总和 | |
MAX | 最大值 | |
MIN | 最小值 | |
AVG | 平均值 |
对数值型数据使用AVG
和SUM
函数,可以对任意数据类型的数据使用MIN
和MAX
函数。
select
max(sal) 最高工资,
min(sal) 最低工资,
avg(sal) 平均工资,
sum(sal) 所有员工的工资和,
count(sal) 领工资的员工数量
from emp;
3.4COUNT函数
- COUNT(*) 返回表中记录总数
- COUNT(expr) 返回expr不为空的记录总数
- COUNT(DISTINCT expr) 返回expr非空且不重复的记录总数
select count(*),count(comm),count(distinct sal) from emp;
3.5组函数忽略空值
注意: 组函数会自动过滤null值。
例,查询所有员工的平均奖金(有人的奖金为null)
SQL> select sum(comm)/count(*) 平均奖金 from emp;
平均奖金
----------
146.666667
SQL> select avg(comm) from emp;
AVG(COMM)
----------
550
在组函数中使用NVL函数,NVL函数使分组函数无法忽略空值。
SQL> select avg(nvl(comm, 0)) from emp;
AVG(NVL(COMM,0))
----------------
146.666667
3.6分组数据
可以使用GROUP BY
子句将表中的数据分成若干组。
GROUP BY
,写在FROM后,如果有WHERE,就在WHERE后面。
①在SELECT列表中所有未包含在组函数中的列都应该包含在GROUP BY子句中。
select deptno,avg(sal) from emp group by deptno;
②包含在GROUP BY子句中的列不必包含在SELECT列表中。
select avg(sal) from emp group by deptno;
③按一个列分组
④按多个列分组,注意:GROUP BY子句中不能使用列别名。
select deptno deptid,job,sum(sal) from emp group by deptno,job;
参与分组的多个列有一个不相同就是不同的组。
⑤不能在WHERE子句中使用组函数,可以在HAVING子句中使用组函数。
3.7过滤分组
使用HAVING
子句过滤分组:
行已经被分组,分完组后再进行过滤,只显示满足HAVING子句中条件的结果。HAVING
子句中使用了组函数。
在GROUP BY
与HAVING
中都不可以使用别名。
与WHERE
的区别:
HAVING
是分完组后再进行过滤。
WHERE
是先过滤,再进行分组操作。
如果可以,尽量写WHERE
条件,不写HAVING
。
select
deptno deptid,job,sum(sal)
from emp
group by deptno,job
having sum(sal) > 4000
order by deptid;
3.8组函数嵌套
显示平均工资的最大值:
select max(avg(sal)) from emp group by deptno;