【Oracle学习08】单行函数与转换函数

553 阅读10分钟

【Oracle学习08】单行函数与转换函数

8.1 描述和使用SQL中的字符、数字和日期函数

8.1.1 函数定义

函数定义: 接收输入参数,执行运算并返回单个值的程序。每次执行时,函数只返回一个值。 函数输入参数可以为0或多个。函数可以嵌套在其它函数中。

8.1.2 函数类型:

函数类型

Single-row SQL functions

Single-row Function

字符串函数

  • 单行函数: 单行函数(Single-row SQL functions)每次只做作用于数据集的一行,若行有5行,则要执行5次。 如字符,数字,日期,转换函数和通用函数都是单行函数。
#length执行了4次,即结果集的次数
select region_id,region_name ,length(region_name) from hr.regions;
  • 多行函数: 函数用于多行。 通常用于求和或平均值,记录总数。 有时称为聚合函数或分组函数。

8.1.3 大小写转换函数

#
select lower(100+200),lower('SQL'),lower('sysdate') from dual;
select first_name,last_name,lower(last_name) from hr.employees 
 where lower(last_name) like '%ur%';

# UPPER
select * from hr.countries where upper(country_name) like '%U%S%A%';

#INITCAP 首字母大写,其它字母小写。 
SQL> select initcap(' init  CAP or init_cap  or init%cap') as initcap from dual;
INITCAP
----------------------------------------------------------------------
 Init  Cap Or Init_Cap  Or Init%Cap

8.1.4 字符串操作函数

字符串操作函数

  • Trim : TRIM只能截取一个字符
#CONCAT
SQL> select concat('Today is:',sysdate) from dual;
CONCAT('TODAYIS:',SYSDATE)
--------------------------------------------------------
Today is:2020-01-21 03:43:22

#LENGTH
select * from hr.countries where length(country_name) > 10;

# LPAD/RPAD 函数 ,填充到指定位数。若是大于指定位数,就会截止
select rpad(first_name || ' ' || last_name,18) || ' earns ' || lpad(salary,6,' ' )  from hr.employees where department_id=100;

# TRIM函数
# TRIM只能截取一个字符。
SQL> select trim(trailing 'son' from 'Anderson') from dual;
ORA-30001: trim set should have only one character

SQL> select trim(both '*' from '**Hiden**'), trim(leading '*' from '**Hiden**') , trim(trailing '*' from '**Hiden**') from dual;

TRIM(BOTH' TRIM(LEADING'* TRIM(TRAILING'
---------- -------------- --------------
Hiden      Hiden**        **Hiden

#INSTR 搜索字符串在给定字符串的位置,返回数字位置
#instr( string1, string2 [, start_position [, nth_appearance ] ] )   // instr(源字符串, 目标字符串, 起始位置, 匹配序号)
select instr('1#3#5#7#9#','#') from dual;
select instr('1#3#5#7#9#','#',5) from dual;
select instr('1#3#5#7#9#','#',3,4) from dual;  -- 第三个字符开始,第4次出现的位置。
INSTR('1#3#5#7#9#','#',3,4)
---------------------------
                         10

#SUBSTR 指定位置取子字符串,substr( string, start_position, [ length ] )
SQL> select substr('1#3#5#7#9#',5) from dual;
SUBSTR('1#3#
------------
5#7#9#

select substr('1#3#5#7#9#',5,3) from dual; --第5个字符开始取3个。
SUBSTR
------
5#7
select substr('1#3#5#7#9#',-3,2) from dual;  --倒数第3个字符开始,取2个字符。
SUBS
----
#9

## replace(原字段,“原字段旧内容“,“原字段新内容“)
update demo set name = replace(name,'医院','医院住院部')
SQL> select replace('1#3#5#7#9#','#','->') from dual;
REPLACE('1#3#5#7#9#','#','->')
------------------------------
1->3->5->7->9->
SQL> select replace('1#3#5#7#9#','#') from dual; -- 用null替换#,即删除#号
REPLACE('1
----------
13579

字符串综合示例:

#到出hostname信息。
define  email='thx@hostname.163.com';
select instr('&email','@') from dual; #pos=4
select substr('&email',instr('&email','@')+1) from dual; # hostname.163.com 
SUBSTR('THX@HOSTNAME.163.COM',IN
--------------------------------
hostname.163.com

select substr('&email',instr('&email','@')+1, instr('&email','.163.com')-instr('&email','@')-1) from dual; #到hostname
SUBSTR('THX@HOST
----------------
hostname

8.1.5 数字函数

数字函数

ROUND:

#数字函数
SQL> SELECT TRUNC(45.923,2), TRUNC(45.923),  TRUNC(45.923,-1)  FROM   DUAL;
TRUNC(45.923,2) TRUNC(45.923) TRUNC(45.923,-1)
--------------- ------------- ----------------
          45.92            45               40

#ROUND 函数,对n+1位4舍5入.
SQL> select round(1601.916,1) from dual;
ROUND(1601.916,1)
-----------------
           1601.9
SQL> select round(-1601.916,1) from dual;
ROUND(-1601.916,1)
------------------
           -1601.9
SQL> select round(1601.916,2) from dual;
ROUND(1601.916,2)
-----------------
          1601.92
SQL> select round(1601.916,-3) from dual;
ROUND(1601.916,-3)
------------------
              2000

TRUNC:

#Truncate
SQL> select trunc(1601.916,1) from dual; --  1601.9
SQL> select trunc(1601.916,2) from dual; -- 1601.91
SQL>  select trunc(1601.916,-3) from dual;
TRUNC(1601.916,-3)
------------------
              1000

SQL> SELECT TRUNC (ROUND(156.00,-2),-1) FROM DUAL;
TRUNC(ROUND(156.00,-2),-1)
--------------------------
                       200

MOD

#Modulus
SQL> select mod(6,2) from dual;
  MOD(6,2)
----------
         0
SQL> select mod(5,3) from dual;
  MOD(5,3)
----------
         2

8.1.6 日期

日期函数:

  • SYSDATE,ADD_MONTHS,MONTHS_BETWEEN,LAST_DAY,NEXT_DAY,ROUND,TRUNC. 日期相减是数字类型。
  • TO_NUMBER(SYSDATE)
  • TO_DATE : 和NLS_DATE_FORMAT要一致
  • Default 格式是 'DD-MM-RR'

日期函数

日期表示

日期计算

#日期
SELECT SESSIONTIMEZONE, CURRENT_DATE,CURRENT_TIMESTAMP FROM DUAL;
SESSIONTIMEZONE CURRENT_DATE CURRENT_TIMESTAMP
--------------------------------------------------------------------------------
+08:00 2020-01-24 06:15:16  24-JAN-20 06.15.16.049367 AM +08:00

SQL> select ROUND(SYSDATE,'MONTH'), ROUND(SYSDATE,'YEAR'),TRUNC(SYSDATE,'MONTH'),TRUNC(SYSDATE,'YEAR') from dual;

ROUND(SYSDATE,'MONT ROUND(SYSDATE,'YEAR TRUNC(SYSDATE,'MONT TRUNC(SYSDATE,'YEAR
------------------- ------------------- ------------------- -------------------
2020-02-01 00:00:00 2020-01-01 00:00:00 2020-01-01 00:00:00 2020-01-01 00:00:00


SQL> SELECT last_name, (SYSDATE-hire_date)/7 AS WEEKS  FROM   employees WHERE  department_id = 90;
LAST_NAME                                               WEEKS
-------------------------------------------------- ----------
King                                               1701.32318
Kochhar                                            1583.18032
De Haan                                            1410.32318


SQL> select sysdate from dual;
SYSDATE
-------------------
2020-01-21 06:19:51
SQL> select sysdate-2 from dual;
SYSDATE-2
-------------------
2020-01-19 06:22:09

#日期-->字符串
SQL>  select to_char(sysdate,'YYYY-MM-DD W HH24:MI:SS') from dual; 
TO_CHAR(SYSDATE,'YYYY-MM-DDWHH24:MI:SS')
------------------------------------------
2020-01-21 3 06:30:23

# 字符串-->日期
select * from nls_session_parameters where PARAMETER='NLS_DATE_FORMAT';
SQL> alter session set NLS_DATE_FORMAT='DD-MON-RR';
SQL> select add_months(SYSDATE,6) from dual;
ADD_MONTHS(S
------------
25-JUL-20
select TO_DATE(ADD_MONTHS(SYSDATE,6),'MON-DD-YYYY') from dual; --ORA-01843: 无效的月份
SQL> select TO_DATE(ADD_MONTHS(SYSDATE,6),'DD-MON-YYYY') from dual;  --ok
TO_DATE(ADD_
------------
25-JUL-20

##
SQL> select to_date('2020-01-07 10:00:00','yyyy-mm-dd hh24:mi:ss') from dual;
TO_DATE('2020-01-07
-------------------
2020-01-07 10:00:00

## Date1- Date2 = num1
SQL> select to_date('2020-01-07 10:00:00','yyyy-mm-dd hh24:mi:ss') - to_date('2020-01-01','yyyy-mm-dd')   from dual;
TO_DATE('2020-01-0710:00:00','YYYY-MM-DDHH24:MI:SS')-TO_DATE('2020-01-01','YYYY-
--------------------------------------------------------------------------------
                                                                      6.41666667

#MONTHS_BETWEEN
SQL> select months_between(sysdate , sysdate-31) from dual;
MONTHS_BETWEEN(SYSDATE,SYSDATE-31)
----------------------------------
                                 1
#
SQL> select add_months(to_date('2015.12.29','YYYY/MM/DD'),1) from dual;
ADD_MONTHS(TO_DATE(
-------------------
2016-01-29 00:00:00

#
SQL> select add_months(to_date('07-APR-2009','DD-Mon-YYYY'),2.5) from dual;
ADD_MONTHS(TO_DATE(
-------------------
2009-06-07 00:00:00

# NEXT_DAY(start_date , day of the week) 下一个星期几出现的日期 
SQL> select next_day(to_date('01-JAN-2020','DD-MON-YYYY'),'tue') from dual;

NEXT_DAY(TO_DATE('0
-------------------
2020-01-07 00:00:00
 select next_day(sysdate,'mon') from dual;  查询出下一个星期一是哪一天

#last_day函数的使用是返回指定日期月份的最后一天
SQL>  select last_day(sysdate) from dual;
LAST_DAY(SYSDATE)
-------------------
2020-01-31 07:07:59

#ROUND 日期的4舍5入
SQL> select sysdate from dual;
SYSDATE
-------------------
2020-01-21 07:11:22

SQL> select round(sysdate) day , round(sysdate,'w') week,round(sysdate,'month') month ,round(sysdate,'year') year from dual;

DAY                 WEEK                MONTH               YEAR
------------------- ------------------- ------------------- -------------------
2020-01-21 00:00:00 2020-01-22 00:00:00 2020-02-01 00:00:00 2020-01-01 00:00:00

#TRUNC 函数 ,可对日期截取
SQL> select trunc(sysdate) from dual; 
TRUNC(SYSDATE)
-------------------
2020-01-21 00:00:00

SQL> select trunc(sysdate) day , trunc(sysdate,'w') week,trunc(sysdate,'month') month ,trunc(sysdate,'year') year from dual;

DAY                 WEEK                MONTH               YEAR
------------------- ------------------- ------------------- -------------------
2020-01-21 00:00:00 2020-01-15 00:00:00 2020-01-01 00:00:00 2020-01-01 00:00:00

8.2 SQL中可用的类型转换函数

SQL 转换函数是单行函数,如TO_CHAR, TO_NUMBER,TO_DATE。

conversion

隐式转换

显式转换

1)隐式数据类型转换

#数字转字符,日期转字符
select length(12345678) from dual;
select sysdate from dual; #
select length(sysdate) from dual;

#字符转数字
select mod('123',2) from dual; -- 1
SQL> select mod('11.123',2) from dual; 
MOD('11.123',2)
---------------
          1.123
>select mod('11.123.123',2) from dual; --会出错。
#字串到日期
select add_months('24-JAN-09',1) from dual;
ADD_MONTHS('24-JAN-
-------------------
0024-02-09 00:00:00
SQL>  select add_months(to_date('2015.12.29','YYYY/MM/DD'),1) from dual;
ADD_MONTHS(TO_DATE(
-------------------
2016-01-29 00:00:00

2)显式数据类型转换

#TO_CHAR
SQL> select to_char(0001), to_char(0001,'099999') from dual;
TO TO_CHAR(0001,'
-- --------------
1   000001

#||后要接单引号
SQL> select to_char(0001) || " is a special number" from dual; --error
ORA-00904: " is a special number": invalid identifier

SQL> select to_char(0001) || ' is a special number' from dual; --ok
TO_CHAR(0001)||'ISASPECIALNUMBER'
------------------------------------------
1 is a special number

#
SQL> select 1 || 'is a special number' from dual; --ok
1||'ISASPECIALNUMBER'
----------------------------------------
1is a special number
#
SQL> select to_char(14,'L0999') from dual;
TO_CHAR(14,'L0999')
------------------------------
          $0014

8.3 使用TO_CHAR,TO_NUMBER,TO_DATE

国家语言支持参数(nls_parameters) 对于指定返回日期和数字元素的语言和格式非常有用。

TO_CHAR

Date Format Model

Date Format

TO_CHAR With Number

TO_CHAR and TO_DATE

#nls_session_parameters
select * from nls_session_parameters;
select * from nls_session_parameters where PARAMETER='NLS_DATE_FORMAT';
alter session set NLS_DATE_FORMAT='DD-MON-RR'; --RR是相当于YY,year


SQL> select to_char(sysdate,'fmDD Month YYYY') as today from dual;
TODAY
------------------------------------------------------------
24 January 2020

# FM去除前导0,即01-->1
SQL> select to_char(to_date('2020-01-21','YYYY-MM-DD'),'DD-MM-YYYY') from dual;
TO_CHAR(TO_DATE('202
--------------------
21-01-2020
SQL> select to_char(to_date('2020-01-21','YYYY-MM-DD'),'fm DD-MM-YYYY') from dual;

TO_CHAR(TO_DATE('202
--------------------
 21-1-2020

SQL> select to_char(30.1,'$99,999.99') from dual;
TO_CHAR(30.1,'$99,999.
----------------------
     $30.10

SQL> SELECT last_name, TO_CHAR(hire_date, 'DD-Mon-YYYY') FROM  employees
 WHERE hire_date < TO_DATE('01-Jan-90','DD-Mon-RR');

LAST_NAME                                          TO_CHAR(HIRE_DATE,'DD-MON-YYYY')
-------------------------------------------------- ----------------------------------------
Whalen                                             17-Sep-1987
King                                               17-Jun-1987
Kochhar                                            21-Sep-1989

日期转换操作:

  • TO_CHAR
#TO_CHAR
select to_char(sysdate,'YYYY-MM-DD') from dual;
select to_char(sysdate,'year') from dual;
select to_char(sysdate,'day') from dual;
SQL> select to_char(sysdate,'HH24:MI:SS AM') from dual;
TO_CHAR(SYSDATE,'HH24:
----------------------
11:52:53 AM

SQL> select to_char(sysdate) from dual;
TO_CHAR(SYSDATE)
--------------------------------------
2020-01-21 16:02:32

SQL> select to_char(sysdate,'Month') from dual;
TO_CHAR(SYSDATE,'MONTH')
------------------------------------------------------------------------
January
#
SQL>  select TO_CHAR(TO_DATE('01-JAN-00','DD-MON-RR'),'Day')  from dual;
TO_CHAR(TO_DATE('01-JAN-00','DD-MON-RR'),'DAY')
------------------------------------------------------------------------
Saturday

SQL> select to_char(sysdate,'YYYY-MM-DD HH:MI:SS') from dual;
TO_CHAR(SYSDATE,'YYYY-MM-DDHH:MI:SS')
--------------------------------------
2020-01-21 04:09:10

SQL> SELECT last_name, TO_CHAR(hire_date, 'fmDD Month YYYY') AS HIREDATE FROM   employees;

LAST_NAME                                          HIREDATE
------------------------------------- -----------------------------------------------------------------------
OConnell                                           21 June 1999
Grant                                              13 January 2000
  • TO_DATE
SQL> select * from nls_session_parameters where PARAMETER='NLS_DATE_FORMAT';
SQL> select to_date('01-DEC-2010') from dual;
TO_DATE('01-DEC-201
-------------------
0001-12-20 10:00:00

SQL> select to_date('25-DEC','DD-MON') from dual; 
TO_DATE('25-DEC','D
-------------------
2020-12-25 00:00:00

SQL> select to_date('25-DEC') from dual; --出错
ORA-01858: a non-numeric character was found where a numeric was expected
SQL> select to_date('25-DEC-10','fxDD-MON-YYYY') from dual; --出错
ORA-01862: the numeric value does not match the length of the format item

SQL> select to_date('01-DEC-2010','DD-MON-YYYY') from dual;
TO_DATE('01-DEC-201
-------------------
2010-12-01 00:00:00
  • TO_NUMBER
select to_number('$100.55') from dual; --错误
ORA-01722: invalid number
SQL>select to_number('$1,000.55','$99,999.99') from dual; --ok
TO_NUMBER('$1,000.55','$99,999.99')
-----------------------------------
                            1000.55

SQL> select to_number(123.56,'999.9') from dual; --error 。
select to_number(123.56,'999.999') from dual; --right  123.56

8.4 SELECT中应用条件表达式

8.4.1 嵌套函数

嵌套函数

嵌套函数

SQL> select next_day(last_day(sysdate) - 7 ,'tue') from dual;
NEXT_DAY(LAST_DAY(S
-------------------
2020-01-28 20:29:41

8.4.2 条件函数

  • NVL(original,ifnull) : 测试数为空,返回ifnull。original,ifnull要类型相同否则出错。
  • NVL2(orginal,ifnotnull,ifnull): 不为空则返回,ifnotnull,否则返回ifnull。ifnotnull,ifnull类型要相同。
  • NULLIF(expr1,expr2) : 相等,则返回null,否则返回expre1
  • COALESCE: 返回第一个非空值。COALESCE(expr1,expr2) 等价于 NUL(expr1,expr2)。
  • Decode(expr1,comp1,iftrue1,comp2,iftrue2,.,iffalse) : 返回第一个相等的值,否则返回iffalse。
  • Case: 类似if then else。

NVL等函数
case
Decode

#nvl(original,ifnull)要参数类型相同,nvl2第二,第三参数类型也要相同,否则出错。 
#select nvl(10,'abc') from dual; --error
01722. 00000 -  "invalid number"
SQL>select nvl(to_char(10),'abc') from dual; --ok

SQL> select nvl(null,1234) from dual;
NVL(NULL,1234)
--------------
          1234

SQL> select nvl(substr('abc',4),'No substring exists') from dual;
NVL(SUBSTR('ABC',4),'NOSUBSTRINGEXISTS
--------------------------------------
No substring exists

#NVL2
SQL> select nvl2(1234,1,'a string') from dual; -- 会出错。

SQL> select nvl2(null ,1234,5678) from dual;
NVL2(NULL,1234,5678)
--------------------
                5678

# NULLIF
SQL> select nullif(1234,1234) from dual;
NULLIF(1234,1234)
-----------------
null
SQL> select nullif(1234,5678) from dual;
NULLIF(1234,5678)
-----------------
             1234

# coalesce 单词意思为合并
SQL> select coalesce(null,null,'astring') from dual;
COALESCE(NULL,
--------------
astring
# Decode
SQL> select decode(1234,123,'123 is a match') from dual;
D
-
(null)
SQL>  select decode(1234,123,'123 is a match','not match') from dual;
DECODE(1234,123,'1
------------------
not match

SQL> SELECT last_name, salary,
       DECODE (TRUNC(salary/2000, 0),
                         0, 0.00,
                         1, 0.09,
                         2, 0.20,
                         3, 0.30,
                         4, 0.40,
                         5, 0.42,
                         6, 0.44,
                            0.45) TAX_RATE
FROM   employees
WHERE  department_id = 80;

#CASE
 SQL>  select case substr(1234,1,3)  
 when '1234' then '1234 is match'
 when '123' then '123 match'
 else 'no match'
 end 
 from dual;

CASESUBSTR(1234,1,
------------------
123 match

#
SQL> SELECT last_name, salary, NVL(commission_pct, 0),
    (salary*12) + (salary*12*NVL(commission_pct, 0)) AN_SAL
    FROM employees where last_name like 'D%';

LAST_NAME                                              SALARY NVL(COMMISSION_PCT,0)     AN_SAL
-------------------------------------------------- ---------- --------------------- ----------
Davies                                                   3100                     0      37200
De Haan                                                 17000                     0     204000
Dellinger                                                3400                     0      40800
Dilly                                                    3600                     0      43200
Doran                                                    7500                    .3     117000
#
SELECT last_name,  salary, commission_pct,
       NVL2(commission_pct, 
            'SAL+COMM', 'SAL') income
FROM   employees WHERE department_id IN (50, 80);
#
SELECT last_name,salary, 
(CASE WHEN salary<5000 THEN 'Low' 
      WHEN salary<10000 THEN 'Medium' 
      WHEN salary<20000 THEN 'Good' 
      ELSE 'Excellent' 
END) qualified_salary 
FROM employees where rownum<10;

LAST_NAME                                              SALARY QUALIFIED_SALARY
-------------------------------------------------- ---------- ------------------
OConnell                                                 2600 Low
Grant                                                    2600 Low
Whalen                                                   4400 Low
Hartstein                                               13000 Good
Fay                                                      6000 Medium
Mavris                                                   6500 Medium
Baer                                                    10000 Good
Higgins                                                 12000 Good
Gietz                                                    8300 Medium

参考: