单行函数
6.1, 认识单行函数
函数就是和 Java 语言之中的方法的功能是一样的, 都是为了完成某些特定操作的功能支持, 而在 Oracle 数据库里面也包含了大量的单行函数, 这些函数掌握了以后, 可以方便的帮助进行数据库的相关开发.
对开发者而言, 最为重要的就是 SQL 语法和单行函数, 可是 Oracle 中的单行函数的数量是非常多的. 本章只讲解使用, 后面会讲解如何去开发用户自己的函数(PL/SQL 编程)
6.1.1 单行函数语法
funcation_name(列 | 表达式[, 参数 1, 参数 2,])
函数名称(列 | 表达式 | 数值), 而且在 Oracle 书中只讲解基本的一些单行函数.
6.1.2 单行函数分类
字符函数: 接收数据返回具体的字符信息
数值函数: 对数字进行处理, 如: 四舍五入
日期函数: 直接对日期进行相关操作
转换函数: 日期, 字符, 数字之间可以完成互相转换功能
通用函数: Oracle 子句提供的有特色的函数
6.2, 字符函数
一定是以字符数据为主(字符串)
NO. | 函数名称 | 描述 |
---|---|---|
1 | UPPER(列 | 字符串) | 将字符串的内容全部转大写 |
2 | LOWER(列 | 字符串) | 将字符串的内容全部转小写 |
3 | INITCAP(列 | 字符串) | 将字符串的开头首字母大写 |
4 | REPLACE(列 | 字符串, 新的字符串) | 使用新的字符串替换旧的字符串 |
5 | LENGTH(列 | 字符串) | 求出字符串长度 |
6 | SUBSTR(列 | 字符串, 开始点[, 长度]) | 字符串截取 |
7 | ASCII(字符) | 返回与指定字符对应的十进制数字 |
8 | CHR(数字) | 给出一个整数,并返回与之对应的字符 |
9 | RPAD(列 | 字符串, 长度, 填充字符) LPAD(列 | 字符串, 长度, 填充字符) | 在左或右填充指定长度字符串 |
10 | LTRIM(字符串) , RTRIM(字符串) | 去掉左或右空格 |
11 | TRIM(列 | 字符串) | 去掉左右空格 |
12 | INSTR(列 | 字符串, 要查找的字符串, 开始位置, 出现位置) | 查找一个字符串是否在指定位置上出现 |
在这里有一个问题就会出现, 在 Oracle 里面所有的验证操作必须存在在完整的 SQL 语句之中, 所以如果现在只是进行功能验证, 使用的是一张具体的表.
scott 用户下:
- SELECT UPPER('li xing hua')
- FORM emp;
这个时候发现结果被重复显示了 14 行, 所以现在函数的功能的确是进行了验证, 但是代价太高. 如果使用 DISTINCT 可以消除, 那么如果 emp 表中的数据很多呢? 那么中间处理的数据量就会很大, 所以现在就希望有一张表可以帮助用户进行验证, 而在 Oracle 里就提供了一个 dual 的数据表(是虚拟表).
范例: 验证 UPPER() 和 LOWER() 函数
- SELECT UPPER('li xing hua'),LOWER('MLDN')
- FORM dual;
范例: 现在查询出雇员姓名是 "smith" 的完整信息, 但是由于失误, 没有考虑到大小写问题, 此时可以使用 UPPER() 函数将全部内容变为大写.
- SELECT *
- FORM emp
- WHERE ename = UPPER('smith');
范例: 查询所有雇员姓名, 要求每个雇员的姓名以首字母大写的形式出现
SELECT ename 原始姓名, INITCAP(ename) 姓名开头首字母大写
FORM emp;
范例: 查询所有雇员信息, 要求将雇员姓名中所有的字母 "A" 替换成 "_"
- SELECT ename,REPLACE(ename,'A','_')
- FORM emp;
范例: 查出姓名长度是 5 的所有雇员信息
- SELECT *
- FORM emp
- WHERE LENGTH(ename) = 5;
范例: 查询出雇员姓名前三个字母是 "JAM" 的雇员信息
那么现在要想办法截取出前三个字符, 截取操作就一定要使用 SUBSTR() 函数, 要注意的是, SUBSTR() 函数有两种形式:
从指定位置截取到结尾: SUBSTR(列 | 字符串, 截取开始点)
截取部分字符串: SUBSTR(列 | 字符串, 截取开始点, 截取个数)
- SELECT *
- FORM emp
- WHERE SUBSTR(ename,1,3) = 'JAM';
或者:
- SELECT *
- FORM emp
- WHERE SUBSTR(ename,0,3) = 'JAM';
注意: 在 Oracle 中, 下标都是从 1 开始, 如果设置为 0, 也会自动将其转换为 1 .
范例: 查询所有 10 部门雇员姓名, 但不显示每个雇员姓名的前三个字母
SELECT ename 原姓名, SUBSTR(ename,3) 截取之后的姓名
- FORM emp
- WHERE deptno = 10;
范例: 显示每个雇员姓名及姓名的后三个字母
要想截取每个姓名之中的后三个, 首先要解决的问题是开始点, 从一个指定的开始点一直截取到结尾, 可是每个雇员的姓名长度是不同的, 那么开始点如何确定呢?
实现一: 使用传统做法, 先求得姓名长度, 然后减 2 确定开始点
SELECT ename 原始姓名, SUBSTR(ename,LENGTH(ename) - 2) 截取之后的姓名
- FORM emp
- WHERE deptno = 10;
实现二: 除了此类做法之外, 也可以设置开始点为负数
SELECT ename 原始姓名, SUBSTR(ename,-3) 截取之后的姓名
- FORM emp
- WHERE deptno = 10;
现在很明显使用第二种最方便, 这个也属于 Oracle 的特色, 不过需要注意的是: Java 语言的字符串下标还是从 0 开始, 而且 Java 里的 substring() 方法是不能设置负数的.
面试题: 请问 Oracle 中的 SUBSTR() 函数的下标开始点是从 0 还是 1 开始?
答: 可以设置为 0, 也可以设置为 1, 即使使用了 0, 那么最终的结果也会将其定义为 1.
范例: 返回指定字符的 ASCII 码
- SELECT ASCII('A'),ASCII('L')
- FORM dual;
范例: 验证 CHR() 函数, 将 ASCII 码变回字符
SELECT CHR(100) FORM dual;
范例: 去掉字符串左边空格 - LTRIM() , 去掉右边空格 - RTRIM()
SELECT 'MLDN LiXingHua' 原始字符串, LTRIM(' ') 去掉左空格
FORM dual;
SELECT 'MLDN LiXingHua' 原始字符串, RTRIM(' ') 去掉右空格
FORM dual;
范例: 去掉左右空格
SELECT 'MLDN LiXingHua' 原始字符串, TRIM(' ') 去掉左右空格
FORM dual;
不管如何取消空格, 中间的空格可是无法消除掉的.
范例: 字符串左填充 - LPAD() , 字符串右填充 - RPAD()
SELECT LPAD('MLDN',10,'*') LPAD 函数使用, RPAD('MLDN',10,'*') RPAD 函数使用,
LPAD(RPAD('MLDN',10,'*'),16,'*') 组合使用
FORM dual;
范例: 字符串查找 - INSTR()
SELECT
INSTR('MLDN Java','MLDN') 查找得到,
INSTR('MLDN Java','Java') 查找得到,
INSTR('MLDN Java','JAVA') 查找不到
FORM dual;
这个函数和 Java 中的 indexOf() 方法功能是相同的.
小结:
字符函数的主要功能是进行字符串数据的操作
6.3, 数值函数
No. | 函数名称 | 描述 |
---|---|---|
1 | ROUND(数字[, 保留小数]) | 对小数进行四舍五入,可以指定保留位数,如果不指定,则表示将小数点之后的数字全部进行四舍五入 |
2 | TRUNC(数字[, 截取位数]) | 保留指定位数的小数,如果不指定,则表示不保留小数 |
3 | MOD(数字, 数字) | 取模 |
范例: 验证 ROUND() 函数的使用
SELECT
ROUND(789.652) 不保留小数,
ROUND(789.652,2) 不保留小数,
ROUND(789.652,-1) 不保留小数,
FROM dual;
范例: 列出每个雇员的一些基本信息和日工资情况
对于日工资的计算可以采用 30 天为基础, 肯定会有小数, 就保留 2 位
SELECT empno,ename,job,hiredate,sal,ROUND(sal/30,2) 日薪金
FROM emp;
ROUND() 函数的功能是小数进位, 而 TRUNC() 的功能是不进位.
范例: 验证 TRUNC() 函数的使用
SELECT
TRUNC(789.652) 截取小数,
TRUNC(789.652,2) 截取 2 位小数,
TRUNC(789.652,-2) 取整
FROM dual;
范例: MOD() 函数验证, 模就是取余
SELECT MOD(10,3) FROM dual;
6.4, 日期函数
如果现在要想进行日期的操作, 那一定会存在一个前提, 必须知道当前日期
取得当前的系统时间, 可以直接利用 SYSDATE 伪列取得当前日期时间. 所谓伪列指的是不是表中的列, 但是有可以直接使用的列.
- SELECT empno,ename,SYSDATE FROM emp;
- SELECT SYSDATE FROM dual;
在默认情况下显示的内容, 只包含了年, 月, 日三个内容, 如果要显示更多内容, 就必须修改语言环境.
修改日期显示格式:
运行 - sqlplus/nolog - conn c##scott/tiger
输入以下代码
- ALTER SESSION SET NLS_DATE_FORMAT = 'yyyy-mm-dd hh24:mi:ss';
- SELECT SYSDATE FROM dual;
更改的日期显示格式在关闭窗口重新打开后就会还原了
除了取得系统时间的操作之外, 在 Oracle 中也有如下的三个日期操作公式:
日期 - 数字 = 日期, 表示若干天前的日期
日期 + 数字 = 日期, 表示若干天后的日期
日期 - 日期 = 数字(天数), 表示两个日期的天数的间隔
可是绝对不会存在 "日期 + 日期" 的计算, 下面为其验证.
SELECT
SYSDATE+3 三天之后的日期,
SYSDATE-3 三天之前的日期
FROM dual;
范例: 查询出每个雇员的到今天为止的雇佣天数, 以及十天前每天雇员的雇佣天数
SELECT empno 雇员编号, ename 雇员姓名,
SYSDATE-hiredate 雇佣天数,
(SYSDATE-10)-hiredate 10 天前雇佣天数
FROM emp;
结果有小数点, 可以用 TRUNC() 截取小数点
SELECT empno 雇员编号, ename 雇员姓名,
TRUNC(SYSDATE-hiredate) 雇佣天数,
TRUNC((SYSDATE-10)-hiredate) 10 天前雇佣天数
FROM emp;
以上只是针对于当前时间的操作, 对于 Oracle 而言, 也提供相应的日期函数, 之所以使用日期函数, 主要是避免闰年问题, 或者是一个月有 28,29,30,31 天的问题, 通过日期函数的计算取得的日期时间是最准确的.
No. | 函数名称 | 描述 |
---|---|---|
1 | ADD_MONTHS(日期, 数字) | 在指定的日期上加入指定的月数,求出新的日期 |
2 | MONTHS_BETWEEN(日期 1, 日期 2) | 求出两个日期间的雇佣月数 |
3 | NEXT_DAY(日期, 星期数) | 求出下一个星期几的具体日期 |
4 | LAST_DAY(日期) | 求出指定日期所在月的最后一天日期 |
5 | EXTRACT(格式 FROM 数据) | 日期时间分隔,或计算给定两个日期的间隔 |
范例: 验证 ADD_MONTHS() 函数
使用 ADD_MONTHS() 函数的主要功能是在一个指定日期上增加若干个月之后求得的新日期.
SELECT SYSDATE,
ADD_MONTHS(SYSDATE,3) 三个月之后的日期,
ADD_MONTHS(SYSDATE,-3) 三个月之前的日期,
ADD_MONTHS(SYSDATE,60) 六十个月之后的日期,
FROM dual;
范例: 要求显示所有雇员在被雇佣三个月之后的日期
- SELECT empno,ename,job,sal,hiredate,ADD_MONTHS(hiredate,3)
- FROM emp;
范例: 验证 NEXT_DAY() 函数
主要是求出下一个指定的日期数, 如果说现在的日期是'2019 年 08 月 30 日 星期五' , 那么如果现在想要知道下一个'星期一' 或是 '星期日' 的具体日期, 则可以使用 NEXT_DAY() 函数.
- SELECT
- SYSDATE,
NEXT_DAY(SYSDATE,'星期日') 下一个星期日,
NEXT_DAY(SYSDATE,'星期一') 下一个星期一
FROM dual;
范例: LAST_DAY() 函数验证, 求当月的最后一天
- SELECT SYSDATE,
- LAST_DAY(SYSDATE)
- FROM dual;
范例: 查询所有是在其雇佣所在月的倒数第三天被公司雇佣的完整雇佣信息
每一位雇员都有自己的雇佣日期, 那么现在要查询出, 你雇佣日期所在月倒数第三天雇佣的人, 首先需要知道的是每个雇员雇佣所在月的最后一天.
- SELECT empno,ename,job,hiredate,LAST_DAY(hiredate)
- FROM emp
- WHERE LAST_DAY(hiredate)-2=hiredate;
范例: MONTHS_BETWEEN() 函数的验证: 查询出每个雇员的编号, 姓名, 雇员佣日期, 雇佣的月数及年份
MONTHS_BETWEEN() 函数的功能是取得两个日期时间的月份间隔
SELECT
empno 雇员编号, ename 雇员姓名, hiredate 雇佣日期,
TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)) 雇佣总月数,
TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)/12) 雇佣总年数
FROM emp;
范例: 查询出每个雇员的编号, 姓名, 雇佣日期, 已雇佣的年数, 月数, 天数
对于本程序而言, 一定是分步计算, 而且有一定的难度, 因为要操作的是准确性.
例如, 今天的日期是 2019-09-01 日, 而 BLAKE 的雇佣日期是 1981-05-01, 那么这位雇员到今天为止被雇佣了 38 年, 4 个月, 0 天.
步骤一: 求出年, 年只需要依靠月就可以计算出来.
SELECT
empno 雇员编号, ename 雇员姓名, hiredate 雇佣日期,
TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)/12) 雇佣总年数
FROM emp;
步骤二: 求出月, 计算年的时候存在小数, 那么这里面的数据就是月, 只需要求模即可得到.
SELECT
empno 雇员编号, ename 雇员姓名, hiredate 雇佣日期,
TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)/12) 已雇佣年数,
TRUNC(MOD(MONTHS_BETWEEN(SYSDATE,hiredate),12)) 已雇佣月数
FROM emp;
步骤三: 是针对于天的计算, 因为现在已经计算出了年和月, 所以天应该刨去年和月的数字信息. 那么现在的问题是, 如果要想计算天数唯一知道的公式就是 "日期 1 - 日期 2", 那么日期 1 一定使用的是 SYSDATE , 而日期 2(应该去掉年和月), 可以利用 ADD_MONTHS() 函数实现此功能.
SELECT
empno 雇员编号, ename 雇员姓名, hiredate 雇佣日期,
TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)/12) 已雇佣年数,
TRUNC(MOD(MONTHS_BETWEEN(SYSDATE,hiredate),12)) 已雇佣月数,
TRUNC(SYSDATE - ADD_MONTHS(hiredate,MONTHS_BETWEEN(SYSDATE,hiredate))) 已雇佣天数
FROM emp;
范例: EXTRACT() 函数
在 Oracle 9i 之后增加了一个 EXTRACT() 函数, 此函数的主要功能是可以从一个日期时间 (DATE) 或者是时间间隔 (INTERVAL) 中截取出特定的部分, 此函数使用语法如下:
- EXTRACT
- ([YEAR | MONTH | DAY | HOUR | MINUTE | SECOND]
- | [TIMEZONE_HOUR | TIMEZONE_MINUTE]
- | [TIMEZONE_REGION | TIMEZONE_ABBR]
- FROM
[日期(date_value) | 时间间隔(interval_value)]);
范例: 从日期时间之中取出年, 月, 日数据
- SELECT
- EXTRACT(YEAR FROM DATE '2001-09-19') years,
- EXTRACT(MONTH FROM DATE '2001-09-19') months,
- EXTRACT(DAY FROM DATE '2001-09-19') days
- FROM dual;
现在是通过一个日期的字符串完成, 那么也可以利用当前日期完成. SYSDATE,SYSTIMESTAMP(时间戳).
- SELECT SYSDATE,SYSTIMESTAMP
- FROM dual;
范例: 从时间戳之中取出年, 月, 日, 时, 分, 秒
- SELECT
- EXTRACT(YEAR FROM SYSTIMESTAMP) years,
- EXTRACT(MONTH FROM SYSTIMESTAMP) months,
- EXTRACT(DAY FROM SYSTIMESTAMP) days,
- EXTRACT(HOUR FROM SYSTIMESTAMP) hours,
- EXTRACT(MINUTE FROM SYSTIMESTAMP) minutes,
- EXTRACT(SECOND FROM SYSTIMESTAMP) seconds
- FROM dual;
除了以上功能之外, 主要功能是取得时间间隔, 但是在此处需要使用到一个转换函数: TO_TIMESTAMP() , 可以将字符串变为时间戳, 而且此时的内容需要使用到部分子查询功能, 所以此处只为做个演示.
范例: 取得两个日期之间的间隔
- SELECT
- EXTRACT(DAY FROM TO_TIMESTAMP('1982-08-13 12:17:57','yyyy-mm-dd hh24:mi:ss')
- - TO_TIMESTAMP('1981-09-27 09:08:33','yyyy-mm-dd hh24:mi:ss')) days
- FROM dual;
范例: 取得两个日期时间之间间隔的天, 时, 分, 秒
- SELECT
- EXTRACT(DAY FROM datetime_one - datetime_two) days,
- EXTRACT(HOUR FROM datetime_one - datetime_two) hours,
- EXTRACT(MINUTE FROM datetime_one - datetime_two) minutes,
- EXTRACT(SECOND FROM datetime_one - datetime_two) seconds
- FROM (
- SELECT TO_TIMESTAMP('1982-08-13 12:17:57','yyyy-mm-dd hh24:mi:ss') datetime_one,
- TO_TIMESTAMP('1981-09-27 09:08:33','yyyy-mm-dd hh24:mi:ss') datetime_two
- FROM dual);
如果觉得比较麻烦, 也可以不使用子查询, 按原来的方法写代码就如下:
- SELECT
- EXTRACT(DAY FROM TO_TIMESTAMP('1982-08-13 12:17:57','yyyy-mm-dd hh24:mi:ss')
- - TO_TIMESTAMP('1981-09-27 09:08:33','yyyy-mm-dd hh24:mi:ss')) days,
- EXTRACT(HOUR FROM TO_TIMESTAMP('1982-08-13 12:17:57','yyyy-mm-dd hh24:mi:ss')
- - TO_TIMESTAMP('1981-09-27 09:08:33','yyyy-mm-dd hh24:mi:ss')) hours,
- EXTRACT(MINUTE FROM TO_TIMESTAMP('1982-08-13 12:17:57','yyyy-mm-dd hh24:mi:ss')
- - TO_TIMESTAMP('1981-09-27 09:08:33','yyyy-mm-dd hh24:mi:ss')) minutes,
- EXTRACT(SECOND FROM TO_TIMESTAMP('1982-08-13 12:17:57','yyyy-mm-dd hh24:mi:ss')
- - TO_TIMESTAMP('1981-09-27 09:08:33','yyyy-mm-dd hh24:mi:ss')) seconds
- FROM dual;
这样看来, 第二种方式就是最差的一种方式了, 不推荐使用.
6.5, 转换函数
在数据库之中主要使用的数据类型: 字符, 数字, 日期(时间戳), 那么这三种数据类型之间就需要实现转换操作, 这就属于转换函数的功能.
No. | 函数名称 | 描述 |
---|---|---|
1 | TO_CHAR(日期 | 数字 | 列, 转换格式) | 将指定的数据按照指定的格式变为字符串型 |
2 | TO_DATE(字符串 | 列, 转换格式) | 将指定的字符串按照指定的格式变为 DATE 型 |
3 | TO_NUMBER(字符串 | 列) | 将指定的数据类型变为数字型 |
6.5.1 TO_CHAR() 函数
在默认的情况下, 如果查询一个日期, 则日期默认的显示格式为 "31-1 月 - 12", 而这样的日期显示效果肯定不如常见的 "2012-01-31" 让人看起来习惯, 所以此时就可以通过 TO_CHAR() 函数对这个显示的日期数据进行格式化(格式化之后的数据是字符串), 但是如果要完成这种格式化, 则首先要熟悉一下格式化日期的替代标记.
日期格式化标记:
No. | 转换格式 | 描述 |
---|---|---|
1 | YYYY | 完整的年份数字表示,年有四位,所以使用 4 个 Y |
2 | Y,YYY | 带逗号的年 |
3 | YYY | 年的后三位 |
4 | YY | 年的后两位 |
5 | Y | 年的最后一位 |
6 | YEAR | 年份的文字表示,直接表示四位的年 |
7 | MONTH | 月份的文字表示,直接表示两位的月 |
8 | MM | 用两位数字来表示月份,月有两位,使用两个 M |
9 | DAY | 天数的文字表示 |
10 | DDD | 表示一年里的天数(001~366) |
11 | DD | 表示一月里的天数(01~31) |
12 | D | 表示一周里的天数(1~7) |
13 | DY | 用文字表示星期几 |
14 | WW | 表示一年里的周数 |
15 | W | 表示一月里的周数 |
16 | HH | 表示 12 小时制,小时是两位数字,使用两个 H |
17 | HH24 | 表示 24 小时制 |
18 | MI | 表示分钟 |
19 | SS | 表示秒,秒是两位数字,使用两个 S |
20 | SSSSS | 午夜之后的秒数字表示(0~86399) |
21 | AM|PM (A.M | P.M) | 表示上午或下午 |
22 | FM | 去掉查询后的前导 0,该标记用于时间模板的后缀 |
在 TO_CHAR() 函数里面, 需要两个参数: 日期数据, 转换格式
范例: 格式化日期时间
SELECT SYSDATE 当前系统时间,
TO_CHAR(SYSDATE,'YYYY-MM-DD') 格式化日期,
TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS') 格式化日期时间,
TO_CHAR(SYSDATE,'FMYYYY-MM-DD HH24:MI:SS') 去掉前导 0 的时间
FROM dual;
注意: 在开发中一定别取消前导 0
范例: 使用其他方式格式化年, 月, 日
除了使用标记(是一种习惯, java.text.SimpleDateFormat), 也可以使用单词表示
SELECT SYSDATE 当前系统时间,
TO_CHAR(SYSDATE,'YEAR-MONTH-DAY') 格式化日期
FROM dual;
或者:
SELECT SYSDATE 当前系统时间,
TO_CHAR(SYSDATE,'YEAR-MONTH-DY') 格式化日期
FROM dual;
范例: 查询出所有在每年 2 月份雇佣的雇员信息
- SELECT *
- FROM emp
- WHERE TO_CHAR(hiredate,'MM') = 2;
或者:
- SELECT *
- FROM emp
- WHERE TO_CHAR(hiredate,'MM') = '02';
范例: 将每个雇员的雇佣日期进行格式化显示, 要求所有的雇佣日期可以按照 "年 - 月 - 日" 的形式显示, 也可将雇佣的年, 月, 日拆开分别显示
SELECT empno,ename,job,hiredate,
TO_CHAR(hiredate,'YYYY-MM-DD') 格式化雇佣日期,
TO_CHAR(hiredate,'YYYY') 年,
TO_CHAR(hiredate,'MM') 月,
TO_CHAR(hiredate,'DD') 日
FROM emp;
TO_CHAR() 函数的最为重要的功能是可以将数字格式化, 例如: 2389042809, 如果是有经验的财务人员会按照三位一分: 2,389,042,809 , 而要想按照此方法处理数字, 就必须格式化.
数字格式化标记
No. | 转换格式 | 描述 |
---|---|---|
1 | 9 | 表示一位数字 |
2 | 0 | 表示前导 0 |
3 | $ | 将货币的符号信息显示为美元符号 |
4 | L | 根据语言环境不同,自动选择货币符号 |
5 | . | 显示小数点 |
6 | , | 显示千位符 |
范例: 格式化数字显示
SELECT
TO_CHAR(987654321.789,'999,999,999,999.9999') 格式化数字,
TO_CHAR(987654321.789,'000,000,000,000.0000') 格式化数字
FROM dual;
除了直接对数字格式化, 也可以进行货币的显示
SELECT
TO_CHAR(987654321.789,'L999,999,999,999.9999') 显示货币,
TO_CHAR(987654321.789,'$999,999,999,999.9999') 显示美元
FROM dual;
在开发之中, TO_CHAR() 函数的作用还是非常明显的! 建议掌握!
6.5.2 TO_DATE() 函数
这个函数主要是将字符串变为日期型数据, 而改变的过程里面依然需要之前 TO_CHAR() 函数出现的相关标记.
范例: 转换时间显示
- SELECT
- TO_DATE('1979-09-19','YYYY-MM-DD')
- FROM dual;
在之前讲解日期函数时使用了一个 TO_TIMESTAMP() 函数, 这个函数是将字符串变为时间戳.
范例: 时间戳转换
- SELECT
- TO_TIMESTAMP('1981-09-27 18:07:10','YYYY-MM-DD HH24:MI:SS') datetime
- FROM dual;
6.5.3 TO_NUMBER() 函数
作用是将字符串变为数字
范例: 将字符串变为数字
SELECT
TO_NUMBER('09') + TO_NUMBER('19') 加法操作,
TO_NUMBER('09') * TO_NUMBER('19') 乘法操作
FROM dual;
但是在之前强调过, Oracle 里面支持数据类型的自动转型操作, 上面的代码也可写为
SELECT '09' + '19' 加法操作,
'09' * '19' 乘法操作
FROM dual;
6.6, 通用函数
这些函数是 Oracle 数据库的特色, 对于这些函数了解有一定的好处.
No. | 函数名称 | 描述 |
---|---|---|
1 | NVL(数字 | 列 , 默认值) | 如果显示的数字是 null 的话,则使用默认数值表示 |
2 | NVL2(数字 | 列, 返回结果一(不为空显示), 返回结果二(为空显示)) | 判断指定的列是否是 null,如果不为 null 则返回结果一,为空则返回结果二 |
3 | NULLIF(表达式一, 表达式二) | 比较表达式一和表达式二的结果是否相等,如果相等返回 NULL,如果不相等返回表达式一 |
4 | DECODE(列 | 值, 判断值 1, 显示结果 1, 判断值 2, 显示结果 2,..., 默认值) | 多值判断,如果某一个列(或一个值)与判断值相同,则使用指定的显示结果输出,如果没有满足条件,在显示默认值 |
5 | CASE 列 | 数值 WHEN 表达式 1 THEN 显示结果 1 ... ELSE 表达式 N ... END | 用于实现多条件判断,在 WHEN 之后编写条件,而在 THEN 之后编写条件满足的显示操作,如果都不满足则使用 ELSE 中的表达式处理 |
6 | COALESCE(表达式 1, 表达式 2,... 表达式 n) | 将表达式逐个判断,如果表达式 1 的内容是 null,则显示表达式 2,如果表达式 2 的内容是 null,则显示表达式 3,依次类推,如果表达式 n 的结果还是 null,则返回 null |
对于通用函数而言, 只有两个核心函数: NVL() , DECODE()
6.6.1 使用 NVL() 函数处理 null
在数据库之中, null 是无法进行计算的, 即, 在一个数学计算之中如果存在了 null, 则最后的结果也肯定是 null
范例: 查询出每个雇员的编号, 姓名, 职位, 雇佣日期, 年薪
对于年薪最准确的做法是应该计算 "sal + comm", 可是这个时候 comm 列上是存在了 null 数据的
SELECT empno,ename,job,hiredate,(sal+comm)*12 年薪, sal,comm
FROM emp;
因为 comm 上的内容有的是 null, 而现在发现, 只要是 comm 为 null 的计算, 最终的结果就是 null , 所以在这种情况下需要针对于 null 进行处理, 肯定将 null 变为 0 才合适
范例: 验证 NVL()
- SELECT NVL(null,0),NVL(3,0)
- FROM dual;
这个时候发现如果为 null, 那么就将其变为了 0, 如果不是 null, 就继续使用指定的数值
SELECT empno,ename,job,hiredate,(sal+NVL(comm,0))*12 年薪, sal,comm
FROM emp;
6.6.2 NVL2() 函数
NVL2() 函数是在 Oracle 9i 之后增加的一个新的功能函数, 相比较 NVL() 函数, NVL2() 函数可以同时对为 null 或不为 null 进行分别判断并返回不同的结果
范例: 查询每个雇员的编号, 姓名, 年薪(sal + comm), 基本工资, 奖金
- SELECT empno,ename,job,hiredate,NVL2(comm,sal+comm,sal),sal,comm
- FROM emp;
6.6.3 NULLIF() 函数
NULLIF(表达式一, 表达式二) 函数的主要功能是判断两个表达式的结果是否相等, 如果相等则返回 NULL , 不相等则返回表达式一
范例: 验证 NULLIF() 函数
- SELECT NULLIF(1,1),NULLIF(1,2)
- FROM dual;
范例: 查询雇员编号, 姓名, 职位, 比较姓名和职位的长度
- SELECT empno,ename,job,LENGTH(ename),LENGTH(job),NULLIF(LENGTH(ename),LENGTH(job)) nullif
- FROM emp;
6.6.4 DECODE() 函数
DECODE() 函数是 Oracle 中最有特色的一个函数, DECODE() 函数类似于程序中的 if...else if...else , 但是判断的内容都是一个具体的值, 语法如下:
DECODE(列 | 表达式, 值 1, 输出结果, 值 2, 输出结果, ..., 默认值)
范例: 测试 DECODE() 函数
- SELECT
- DECODE(2,1,'内容为一',2,'内容为二'),
- DECODE(2,1,'内容为一','没有条件满足')
- FROM dual;
范例: 现在雇员表中的工作有以下几种: CLERK: 业务员, SALESMAN: 销售人员, MANAGER: 经理, ANALYST: 分析员, PRESIDENT: 总裁 , 要求查询雇员的姓名, 职位, 基本工资等信息, 但是要求将所有的职位信息都替换为中文显示.
- SELECT ename,sal,
- DECODE(job,
- 'CLERK','业务员',
- 'SALESMAN','销售人员',
- 'MANAGER','经理',
- 'ANALYST','分析员',
- 'PRESIDENT','总裁') job
- FROM emp;
但是需要注意的是, 如果使用 DECODE() 函数判断, 那么所有的内容都要判断, 如果只判断部分内容, 其它内容就会显示 null
6.6.5 CASE 表达式
CASE 表达式是在 Oracle 9i 引入的, 功能与 DECODE() 有些类似, 都是执行多条件判断. 不过严格来讲, CASE 表达式本身并不属于一种函数的范畴, 它的主要功能是针对于给定的列或者字段进行依次判断, 在 WHERE 中编写判断语句, 而在 THEN 中编写处理语句, 最后如果都不满足则使用 ELSE 进行处理.
范例: 显示每个雇员的工资, 姓名, 职位, 同时显示新的工资(新的工资标准: 办事员增长 10%, 销售人员增长 20%, 经理增长 30%, 其他职位的人增长 50%)
- SELECT ename,sal,
- CASE job WHEN 'CLERK' THEN sal * 1.1
- WHEN 'SALESMAN' THEN sal * 1.2
- WHEN 'MANAGER' THEN sal * 1.3
- ELSE sal * 1.5
END 新工资
FROM emp;
6.6.6 COALESCE() 函数
COALESCE(表达式 1, 表达式 2, 表达式 3,... 表达式 n) 函数的主要功能是对 null 进行操作, 采用依次判断表达式的方式完成, 如果表达式 1 为 null, 则显示表达式 2 的内容, 如果表达式 2 的内容为 null, 则显示表达式 3 的内容, 依次类推, 判断到最后如果还是 null, 则最终的显示结果就是 null .
范例: 验证 COALESCE() 函数
- SELECT ename,sal,comm,COALESCE(comm,100,2000),
- COALESCE(comm,null,null)
- FROM emp;
小结:
这些通用函数都具备一些逻辑性的操作在里面, 在以后进行程序编写时还是会使用到的.
NVL() 和 DECODE() 是通用函数的基础, 其他函数都在此函数之上进行功能扩充.
说明: 本学习资料是根据李兴华的 Oracle 开发实战经典整理
来源: http://www.linuxidc.com/Linux/2019-09/160466.htm