Oracle(2)函数、条件表达式、GROUP BY子句、HAVING子句

文章目录

    • 1 函数
    • 2 单行函数
      • 2.1 字符函数
        • 2.1.1 CONCAT()
        • 2.1.2 SUBSTR()
        • 2.1.3 length()
        • 2.1.4 instr()
        • 2.1.5 RPAD()右补全
        • 2.1.6 LPAD()左补全
        • 2.1.7 TRIM()
      • 2.2 数值函数
        • 2.2.1 ROUND()
        • 2.2.2 TRUNC()
        • 2.2.3 MOD()
      • 2.3 使用日期
        • 2.3.1 SYSDATE()
        • 2.3.2 日期的算术运算
        • 2.3.3 months_between()
        • 2.3.4 ADD_MONTHS()
        • 2.3.5 LAST_DAY()
        • 2.3.6 NEXT_DAY()
        • 2.3.7 ROUND()
        • 2.3.8 TRUNC()
    • 3 转换函数
      • 3.1 隐式和显式数据类型转换
      • 3.2 隐式数据类型转换
      • 3.3 显式数据类型转换
      • 3.4 TO_CHAR函数对日期的转换
      • 3.5 TO_CHAR函数对数字的转换
      • 3.6 TO_NUMBER和TO_DATE
      • 3.7 嵌套函数
      • 3.8 通用函数
        • 3.8.1 NVL()
        • 3.8.2 NVL2()
        • 3.8.3 NULLIF()
        • 3.8.4 COALESCE()
    • 4 条件表达式
      • 4.1 CASE表达式
      • 4.2 DECODE函数
    • 5 使用组/分组函数汇总数据
      • 5.1 分组函数
        • 5.1.1 AVG()
        • 5.1.2 SUM()
        • 5.1.3 MAX()/MIN()
        • 5.1.4 COUNT()统计值
        • 5.1.5 STDDEV()标准差
        • 5.1.6 VARIANCE()方差
      • 5.2 分组函数与空值
    • 6 GROUP BY子句
    • 7 HAVING子句
    • 8 嵌套组函数

1 函数

1.作用

  • 对数据进行计算
  • 修改单个数据项
  • 操作行组的输出
  • 格式化显示日期和数字
  • 转换列数据类型

2.类型

  • 单行函数只对单个行进行操作,每行返回一个结果
  • 多行函数可以操作行组来为每组行提供一个结果

2 单行函数

单行函数用于描述SQL中不同类型的函数,在SELECT语句中使用字符,数字和日期函数。

1.作用

  • 操作数据对象
  • 接受函数返回一个结果
  • 只对一行进行变换
  • 每行返回一个结果
  • 可以转换数据类型
  • 可以嵌套
  • 参数可以是列、值或表达式

单行函数用于操作数据项。它们接受一个或多个参数,并为查询返回的每一行返回一个值,可以是:用户提供的值、变量值、列名或表达式。

2.特点

  • 对查询中返回的每一行执行操作
  • 每行返回一个结果
  • 可能返回引用的数据类型不同的数据值
  • 可能需要一个或多个参数
  • 可用于select,where,order by子句;可以嵌套
    3.类型
  • 字符函数
    接受字符输入,可以同时返回字符值和数字值
  • 数字函数
    接受数字输入并返回数值
  • 日期函数
    操作日期数据类型的值(所有日期函数返回的值为日期数据类型,但months_between除外,它返回一个数字)
  • 转换
  • 通用

4.dual表

  • DUAL表是一个“伪表”(虚拟表),只包含一个列DUMMY,数据类型为VARCHAR2(1)。表只包含一行,其DUMMY列的值为X。

  • DUAL表是为了语法上的完整性。

  • 可以用来当计算器、返回日期等测试函数和表达式


SQL> select * from dual;

D
-
X

SQL> select 123*4 from dual;

     123*4
----------
       492

SQL> select sysdate from dual;

SYSDATE
---------
14-MAY-19

2.1 字符函数

大小写转换函数 字符处理函数
LOWER、UPPER、INITCAP CONCAT、SUBSTR、LENGTH、INSTR、LPAD/RPAD、TRIM、REPLACE

Oracle(2)函数、条件表达式、GROUP BY子句、HAVING子句_第1张图片

2.1.1 CONCAT()

链接字符串、列、表达式

  • 将good和dba连接
SQL> select concat('good','dba') from dual;

CONCAT(
-------
gooddba
  • 通过连接符连接
SQL> select ename||' is a '||job from emp;

ENAME||'ISA'||JOB
-------------------------
SMITH is a CLERK
ALLEN is a SALESMAN
WARD is a SALESMAN
JONES is a MANAGER
MARTIN is a SALESMAN
BLAKE is a MANAGER
CLARK is a MANAGER
SCOTT is a ANALYST
KING is a PRESIDENT
TURNER is a SALESMAN
ADAMS is a CLERK
JAMES is a CLERK
FORD is a ANALYST
MILLER is a CLERK

14 rows selected.
  • 通过concat连接
SQL> select concat(concat(ename,' is '),job) a
  2  from emp;

A
-----------------------
SMITH is CLERK
ALLEN is SALESMAN
WARD is SALESMAN
JONES is MANAGER
MARTIN is SALESMAN
BLAKE is MANAGER
CLARK is MANAGER
SCOTT is ANALYST
KING is PRESIDENT
TURNER is SALESMAN
ADAMS is CLERK
JAMES is CLERK
FORD is ANALYST
MILLER is CLERK

14 rows selected.

2.1.2 SUBSTR()

截取字符串

  • 截取第一个字符开始的3个字符
SQL> select substr('oracle',1,3) from dual;

SUB
---
ora
  • 截取倒数第二个字符开始的2个字符
SQL> select substr('oracle',-2,2) from dual;

SU
--
le
  • 取第四个字符开始到最后的所有字符
SQL> select substr('oracle',4) from dual;

SUB
---
cle
  • 取倒数第五个字符到最后的所有字符
SQL> select substr('oracle',-5) from dual;

SUBST
-----
racle

2.1.3 length()

获取字符数

SQL> select length('oracle') from dual;

LENGTH('ORACLE')
----------------
	       6

2.1.4 instr()

  • 后面字符串在前面字符串第一次出现的位置
SQL> select instr('oracle','cle') from dual;

INSTR('ORACLE','CLE')
---------------------
		    4

instr经常用来做判断,判断一个字符串是否在另外一个字符串中

  • 使用字符控制函数:查询名字里有A的名字
SQL> select ename,instr(ename,'A') from emp;

ENAME	   INSTR(ENAME,'A')
---------- ----------------
SMITH			  0
ALLEN			  1
WARD			  2
JONES			  0
MARTIN			  2
BLAKE			  3
CLARK			  3
SCOTT			  0
KING			  0
TURNER			  0
ADAMS			  1
JAMES			  2
FORD			  0
MILLER			  0

14 rows selected.
  • 查询从第 3 个字符开始,*第 4 次出现的位置
SQL> select instr('1*2*3*4*5*','*',3,4) from dual;

INSTR('1*2*3*4*5*','*',3,4)
---------------------------
			 10
  • 查询从倒数第 3 个字符开始向前,*第 2 次出现的位置
SQL> select instr('1*2*3*4*5*','*',-3,2) from dual;

INSTR('1*2*3*4*5*','*',-3,2)
----------------------------
			   6

2.1.5 RPAD()右补全

SQL> select ename,sal,rpad(sal,5,'*') from emp;

ENAME		  SAL RPAD(SAL,5,'*')
---------- ---------- --------------------
SMITH		  800 800**
ALLEN		 1600 1600*
WARD		 1250 1250*
JONES		 2975 2975*
MARTIN		 1250 1250*
BLAKE		 2850 2850*
CLARK		 2450 2450*
SCOTT		 3000 3000*
KING		 5000 5000*
TURNER		 1500 1500*
ADAMS		 1100 1100*
JAMES		  950 950**
FORD		 3000 3000*
MILLER		 1300 1300*

14 rows selected.

2.1.6 LPAD()左补全

SQL> select sal,lpad(sal,4,0),rpad(sal,4,0) from emp;

       SAL LPAD(SAL,4,0)    RPAD(SAL,4,0)
---------- ---------------- ----------------
       800 0800 	    8000
      1600 1600 	    1600
      1250 1250 	    1250
      2975 2975 	    2975
      1250 1250 	    1250
      2850 2850 	    2850
      2450 2450 	    2450
      3000 3000 	    3000
      5000 5000 	    5000
      1500 1500 	    1500
      1100 1100 	    1100
       950 0950 	    9500
      3000 3000 	    3000
      1300 1300 	    1300

14 rows selected.

2.1.7 TRIM()

去掉前后空格,或者从后面串首尾去掉前面字符:

SQL> select trim(' hello ') from dual;

TRIM(
-----
hello

SQL> select length(' hello '),length(trim(' hello ')) from dual;

LENGTH('HELLO') LENGTH(TRIM('HELLO'))
--------------- ---------------------
	      7 		    5

2.2 数值函数

2.2.1 ROUND()

四舍五入到指定的十进制值

SQL> select round(45.368,0) from dual;

ROUND(45.368,0)
---------------
	     45

SQL> select round(45.237,-1) from dual;

ROUND(45.237,-1)
----------------
	      50

SQL> select round(45.932,2) from dual;

ROUND(45.932,2)
---------------
	  45.93

SQL> select round(45.677,2) from dual;

ROUND(45.677,2)
---------------
	  45.68

2.2.2 TRUNC()

截断到指定十进制值

SQL> select trunc(45.675,2) from dual;

TRUNC(45.675,2)
---------------
	  45.67

SQL> select trunc(45.677,2) from dual;

TRUNC(45.677,2)
---------------
	  45.67

2.2.3 MOD()

返回余数

SQL> select mod(1600,300) from dual;

MOD(1600,300)
-------------
	  100

2.3 使用日期

Oracle内部使用数字存储日期:世纪、年、月、日、小时

默认日期格式:DD-MON-RR

2.3.1 SYSDATE()

SYSDATE是一个日期函数,返回当前数据库服务器的日期和时间。可以像使用任何其他列名一样使用SYSDATE。

SQL> select sysdate from dual;

SYSDATE
---------
14-MAY-19

修改当前session日期格式

SQL> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss day';

Session altered.

SQL> select sysdate from dual;

SYSDATE
-----------------------------
2019-05-14 15:10:57 tuesday

SQL> select hiredate from emp;

HIREDATE
-----------------------------
1980-12-17 00:00:00 wednesday
1981-02-20 00:00:00 friday
1981-02-22 00:00:00 sunday
1981-04-02 00:00:00 thursday
1981-09-28 00:00:00 monday
1981-05-01 00:00:00 friday
1981-06-09 00:00:00 tuesday
1987-04-19 00:00:00 sunday
1981-11-17 00:00:00 tuesday
1981-09-08 00:00:00 tuesday
1987-05-23 00:00:00 saturday
1981-12-03 00:00:00 thursday
1981-12-03 00:00:00 thursday
1982-01-23 00:00:00 saturday

14 rows selected.

2.3.2 日期的算术运算

计算方法 计算公式
date+number 加几天(结果还是日期)
date-number 减几天
date-date 两个日期相减返回日期之间的相差天数
date+number/24 加小时到日期上

因为数据库将日期存储为数字,所以可以使用加减法等算术运算符执行计算。

  • 一天以后
SQL> alter session set nls_date_format = 'DD-MON-RR';

Session altered.

SQL> select sysdate from dual;

SYSDATE
---------
14-MAY-19

SQL> select sysdate + 1 from dual; 

SYSDATE+1
---------
15-MAY-19

  • 日期相减计算入职多少年
SQL> select ename,hiredate,round((sysdate-hiredate)/365,0) years from emp;

ENAME	   HIREDATE	  YEARS
---------- --------- ----------
SMITH	   17-DEC-80	     38
ALLEN	   20-FEB-81	     38
WARD	   22-FEB-81	     38
JONES	   02-APR-81	     38
MARTIN	   28-SEP-81	     38
BLAKE	   01-MAY-81	     38
CLARK	   09-JUN-81	     38
SCOTT	   19-APR-87	     32
KING	   17-NOV-81	     38
TURNER	   08-SEP-81	     38
ADAMS	   23-MAY-87	     32
JAMES	   03-DEC-81	     37
FORD	   03-DEC-81	     37
MILLER	   23-JAN-82	     37

14 rows selected.
  • 一小时后
SQL> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss day';

Session altered.

SQL> select sysdate +1/24 from dual;

SYSDATE+1/24
-----------------------------
2019-05-14 16:18:34 tuesday
  • 一分钟后
SQL> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss day';

Session altered.

SQL> select sysdate +1/24 from dual;

SYSDATE+1/24
-----------------------------
2019-05-14 16:18:34 tuesday

2.3.3 months_between()

两个日期相差的月数

SQL> select empno,ename,months_between(sysdate,hiredate) months from emp;

     EMPNO ENAME	  MONTHS
---------- ---------- ----------
      7369 SMITH      460.923843
      7499 ALLEN      458.827069
      7521 WARD       458.762553
      7566 JONES      457.407714
      7654 MARTIN     451.569004
      7698 BLAKE      456.439972
      7782 CLARK      455.181907
      7788 SCOTT      384.859327
      7839 KING       449.923843
      7844 TURNER     452.214166
      7876 ADAMS      383.730295
      7900 JAMES      449.375456
      7902 FORD       449.375456
      7934 MILLER     447.730295

14 rows selected.

2.3.4 ADD_MONTHS()

向指定日期中加上若干月数

  • 日期增加月份,一年前:
SQL> select sysdate,add_months(sysdate,-12) from dual;

SYSDATE 		      ADD_MONTHS(SYSDATE,-12)
----------------------------- -----------------------------
2019-05-14 15:20:53 tuesday   2018-05-14 15:20:53 monday

只有增加月的函数,没有增加年和日的函数

2.3.5 LAST_DAY()

显示本月的最后一天

SQL> select sysdate,last_day(sysdate) from dual;

SYSDATE 		      LAST_DAY(SYSDATE)
----------------------------- -----------------------------
2019-05-14 15:21:25 tuesday   2019-05-31 15:21:25 friday

2.3.6 NEXT_DAY()

下一个

SQL> select next_day(sysdate,'MONDAY') from dual;

NEXT_DAY(SYSDATE,'MONDAY')
-----------------------------
2019-05-20 15:22:00 monday

SQL> select next_day(sysdate,2) from dual;

NEXT_DAY(SYSDATE,2)
-----------------------------
2019-05-20 15:22:38 monday

2.3.7 ROUND()

日期四舍五入

SQL> select sysdate,round(sysdate) from dual;

SYSDATE 		      ROUND(SYSDATE)
----------------------------- -----------------------------
2019-05-14 15:23:01 tuesday   2019-05-15 00:00:00 wednesday

SQL> select sysdate,round(sysdate,'mi') from dual;

SYSDATE 		      ROUND(SYSDATE,'MI')
----------------------------- -----------------------------
2019-05-14 15:26:57 tuesday   2019-05-14 15:27:00 tuesday

SQL> select sysdate,round(sysdate,'DD') from dual;

SYSDATE 		      ROUND(SYSDATE,'DD')
----------------------------- -----------------------------
2019-05-14 15:27:32 tuesday   2019-05-15 00:00:00 wednesday

2.3.8 TRUNC()

日期截断

  • 今年第一天
SQL> select sysdate,trunc(sysdate,'yyyy') from dual;

SYSDATE 		      TRUNC(SYSDATE,'YYYY')
----------------------------- -----------------------------
2019-05-14 15:29:11 tuesday   2019-01-01 00:00:00 tuesday

3 转换函数

3.1 隐式和显式数据类型转换

  • 隐式数据类型转换:在后台转换
  • 显式数据类型转换:数据类型与默认格式匹配

3.2 隐式数据类型转换

  • Oracle服务器自动完成下列转换
From To
VARCHAR2 or CHAR NUMBER
VARCHAR2 or CHAR DATE

Oracle服务器可以在表达式中自动执行数据类型转换。
如,hiredate>‘01-JAN-90’会导致从字符串‘01-JAN-90’到日期的隐式转换。
所以可以隐式地将VARCHAR2或CHAR值转换为表达式中的数字或日期数字类型。

  • char和varchar的区别
    char 长度固定
    varchar2 长度动态变化,先判断,再分配,再看超没超过长度

  • Oracle服务器自动完成下列转换

From To
NUMBER VARCHAR2 or CHAR
DATE VARCHAR2 or CHAR

通常,当需要数据类型转换时,Oracle服务器使用表达式规则。
如,grade列是CHAR(2)类型。表达式grade = 2 将导致数值2隐式转换为字符串”2“

3.3 显式数据类型转换

Oracle(2)函数、条件表达式、GROUP BY子句、HAVING子句_第2张图片

3.4 TO_CHAR函数对日期的转换

TO_CHAR将datetime数据类型转换为format_model指定格式的VARCHAR2数据类型值。
格式模式是描述存储在字符串中的datetime格式的字符文字。
可以使用TO_CHAR函数将日期从其默认格式转换为指定格式。

  • 格式:TO_CHAR(date,‘format_model’)
    1.必须包含在单引号内
    2.大小写敏感
    3.可以包含任意的有效日期格式
    4.可以使用fm去掉多余的空格或者前导零
    5.与日期值用逗号隔开
SQL> select ename,to_char(hiredate,'MM/YY') MON from emp;

ENAME	   MON
---------- -----
SMITH	   12/80
ALLEN	   02/81
WARD	   02/81
JONES	   04/81
MARTIN	   09/81
BLAKE	   05/81
CLARK	   06/81
SCOTT	   04/87
KING	   11/81
TURNER	   09/81
ADAMS	   05/87
JAMES	   12/81
FORD	   12/81
MILLER	   01/82

14 rows selected.

YYYY 完整的年份
YEAR 年(英文)
MM 双位数字月份
MONTH 完整的月份名称
MON 月份的三个字母缩写
DY 星期的三个字母缩写
DAY 完整的星期名称
DD 月份的数字(天)
HH24:MI:SS AM 15:45:32 PM
DD “of” MONTH 12 of OCTOBER
ddspth 日期在月份中的位置(如fourteenth)

3.5 TO_CHAR函数对数字的转换

  • 格式:TO_CHAR(number,‘format_model’)

9 代表一个数字
0 强制显示0
$ 放置一个浮动的美元符号
L 采用浮动本地货币符号
. 打印小数点
, 打印一个逗号作为千位标识符

SQL> select sal,to_char(sal,'$999,999,999.90') s from emp;

       SAL S
---------- ----------------
       800	    $800.00
      1600	  $1,600.00
      1250	  $1,250.00
      2975	  $2,975.00
      1250	  $1,250.00
      2850	  $2,850.00
      2450	  $2,450.00
      3000	  $3,000.00
      5000	  $5,000.00
      1500	  $1,500.00
      1100	  $1,100.00
       950	    $950.00
      3000	  $3,000.00
      1300	  $1,300.00

14 rows selected.

这里,第一列是数字类型,第二列是字符类型

  • 如果位数不够,会显示遗传数字符号####代替,而不是数字超过格式模型中提供的数字的整数
SQL> select sal,to_char(sal,'$999') s from emp;

       SAL S
---------- -----
       800  $800
      1600 #####
      1250 #####
      2975 #####
      1250 #####
      2850 #####
      2450 #####
      3000 #####
      5000 #####
      1500 #####
      1100 #####
       950  $950
      3000 #####
      1300 #####

14 rows selected.

如果在format model里面添加G、D等,是无效的数字默认类型

  • Oracle服务器将存储的decimal值四舍五入到格式模型中提供的小数位数

3.6 TO_NUMBER和TO_DATE

  • 使用TO_NUMBER函数将字符转换为数字格式:
    TO_NUMBER(char[,'format_model])
  • 使用TO_DATE函数将字符转换为日期格式:
    TO_DATE(char[,'format_model'])
  • 字符参数中的标点符号和引号必须与格式模型的相应部分完全匹配(大小写除外)
  • 字符参数不能有额外的空格
  • 字符参数中的数字数据必须与格式模式中的相应元素具有相同的位数。

3.7 嵌套函数

  • 单行函数可以嵌套到任意层数
  • 嵌套函数的执行顺序是由内至外
    Oracle(2)函数、条件表达式、GROUP BY子句、HAVING子句_第3张图片

3.8 通用函数

这些函数适用于任何数据类型,同时也适用于空值

3.8.1 NVL()

NVL (expr1,expr2)转换null值为实际的数值

SQL> select nvl2(comm,0,1000),comm from emp;

NVL2(COMM,0,1000)	COMM
----------------- ----------
	     1000
		0	 300
		0	 500
	     1000
		0	1400
	     1000
	     1000
	     1000
	     1000
		0	   0
	     1000
	     1000
	     1000
	     1000

14 rows selected.

3.8.2 NVL2()

NVL2 (expr1,expr2,expr3)
如果expr1不是null,转换为expr2,如果expr1是空值,则转换为expr3

# 可以输出字符串
SQL> select ename,sal,nvl2(comm,'sal+comm','sal') income from emp;

ENAME		  SAL INCOME
---------- ---------- --------
SMITH		  800 sal
ALLEN		 1600 sal+comm
WARD		 1250 sal+comm
JONES		 2975 sal
MARTIN		 1250 sal+comm
BLAKE		 2850 sal
CLARK		 2450 sal
SCOTT		 3000 sal
KING		 5000 sal
TURNER		 1500 sal+comm
ADAMS		 1100 sal
JAMES		  950 sal
FORD		 3000 sal
MILLER		 1300 sal

14 rows selected.
# 计算收入
SQL> select ename,sal,comm,nvl2(comm,comm+sal,sal) income from emp;

ENAME		  SAL	    COMM     INCOME
---------- ---------- ---------- ----------
SMITH		  800			800
ALLEN		 1600	     300       1900
WARD		 1250	     500       1750
JONES		 2975		       2975
MARTIN		 1250	    1400       2650
BLAKE		 2850		       2850
CLARK		 2450		       2450
SCOTT		 3000		       3000
KING		 5000		       5000
TURNER		 1500	       0       1500
ADAMS		 1100		       1100
JAMES		  950			950
FORD		 3000		       3000
MILLER		 1300		       1300

14 rows selected.

3.8.3 NULLIF()

NULLIF(expr1,expr2)
比较两个表达式,如果它们相等,返回null;如果它们不相等,返回第一个表达式

SQL> select ename,job,length(ename) l1,length(job) l2,
  2  nullif(length(ename),length(job)) l
  3  from emp;

ENAME	   JOB		     L1 	L2	    L
---------- --------- ---------- ---------- ----------
SMITH	   CLERK	      5 	 5
ALLEN	   SALESMAN	      5 	 8	    5
WARD	   SALESMAN	      4 	 8	    4
JONES	   MANAGER	      5 	 7	    5
MARTIN	   SALESMAN	      6 	 8	    6
BLAKE	   MANAGER	      5 	 7	    5
CLARK	   MANAGER	      5 	 7	    5
SCOTT	   ANALYST	      5 	 7	    5
KING	   PRESIDENT	      4 	 9	    4
TURNER	   SALESMAN	      6 	 8	    6
ADAMS	   CLERK	      5 	 5
JAMES	   CLERK	      5 	 5
FORD	   ANALYST	      4 	 7	    4
MILLER	   CLERK	      6 	 5	    6

14 rows selected.

3.8.4 COALESCE()

COALESCE(expr1,expr2,...,exprn)
返回表达式列表中的第一个非空表达式

COALESCE与NVL相比的优点在于COALESCE可以同时处理交替的多个值。如果第一个表达式非空,则返回这个表达式,对其他的参数进行COALESCE。

SQL> select ename,empno,mgr,comm,
  2  coalesce(to_char(comm),to_char(mgr),'No commission and no manager') a  
  3  from emp;

ENAME		EMPNO	     MGR       COMM A
---------- ---------- ---------- ---------- ----------------------------------------
SMITH		 7369	    7902	    7902
ALLEN		 7499	    7698	300 300
WARD		 7521	    7698	500 500
JONES		 7566	    7839	    7839
MARTIN		 7654	    7698       1400 1400
BLAKE		 7698	    7839	    7839
CLARK		 7782	    7839	    7839
SCOTT		 7788	    7566	    7566
KING		 7839			    No commission and no manager
TURNER		 7844	    7698	  0 0
ADAMS		 7876	    7788	    7788
JAMES		 7900	    7698	    7698
FORD		 7902	    7566	    7566
MILLER		 7934	    7782	    7782

14 rows selected.

如果mgr值不是null,就会显示它,如果mgr值为null,则会显示comm。
如果mgr和comm都为null,则显示“没有佣金,就没有经理”
应用to_char函数时,所有表达式应具有相同的数据类型

4 条件表达式

在SQL语句中使用IF-THEN-ELSE逻辑,可以使用CASE表达式和DECODE函数。

4.1 CASE表达式

  • 语法
CASE expr WHEN comparision_expr1 THEN return_expr1
                [WHEN comparision_expr2 THEN return_expr2
                 WHEN comparision_expr3 THEN return_expr3
                 ELSE else_expr]
END

例:

SQL> select ename,job,sal,
  2  case job when 'ANALYST' then 1.5*12*sal
  3  when 'SALESMAN' then 1.4*12*sal
  4  when 'MANAGER' then 1.3*12*sal
  5  else sal end "REVISED_SAL"
  6  from emp;

ENAME	   JOB		    SAL REVISED_SAL
---------- --------- ---------- -----------
SMITH	   CLERK	    800 	800
ALLEN	   SALESMAN	   1600       26880
WARD	   SALESMAN	   1250       21000
JONES	   MANAGER	   2975       46410
MARTIN	   SALESMAN	   1250       21000
BLAKE	   MANAGER	   2850       44460
CLARK	   MANAGER	   2450       38220
SCOTT	   ANALYST	   3000       54000
KING	   PRESIDENT	   5000        5000
TURNER	   SALESMAN	   1500       25200
ADAMS	   CLERK	   1100        1100
JAMES	   CLERK	    950 	950
FORD	   ANALYST	   3000       54000
MILLER	   CLERK	   1300        1300

14 rows selected.

SQL> select ename,job,sal,12*sal yesa,
  2  case when job in('MANAGER','ANALYST') then 1.5*12*sal
  3  when job = 'SALESMAN' then 1.2*12*sal
  4  else 12*sal end "NEW"
  5  from emp;

ENAME	   JOB		    SAL       YESA	  NEW
---------- --------- ---------- ---------- ----------
SMITH	   CLERK	    800       9600	 9600
ALLEN	   SALESMAN	   1600      19200	23040
WARD	   SALESMAN	   1250      15000	18000
JONES	   MANAGER	   2975      35700	53550
MARTIN	   SALESMAN	   1250      15000	18000
BLAKE	   MANAGER	   2850      34200	51300
CLARK	   MANAGER	   2450      29400	44100
SCOTT	   ANALYST	   3000      36000	54000
KING	   PRESIDENT	   5000      60000	60000
TURNER	   SALESMAN	   1500      18000	21600
ADAMS	   CLERK	   1100      13200	13200
JAMES	   CLERK	    950      11400	11400
FORD	   ANALYST	   3000      36000	54000
MILLER	   CLERK	   1300      15600	15600

14 rows selected.

SQL> select ename,job,sal,nvl(comm,0),
  2  case when (sal+nvl(comm,0)) between 1000 and 1500 then 'BAD'
  3  when (sal+nvl(comm,0)) between 1500 and 4000 then 'GOOD'
  4  when (sal+nvl(comm,0)) >4000 then 'VERY GOOD'
  5  else 'NULL' end "GRADE"
  6  from emp;

ENAME	   JOB		    SAL NVL(COMM,0) GRADE
---------- --------- ---------- ----------- ---------
SMITH	   CLERK	    800 	  0 NULL
ALLEN	   SALESMAN	   1600 	300 GOOD
WARD	   SALESMAN	   1250 	500 GOOD
JONES	   MANAGER	   2975 	  0 GOOD
MARTIN	   SALESMAN	   1250        1400 GOOD
BLAKE	   MANAGER	   2850 	  0 GOOD
CLARK	   MANAGER	   2450 	  0 GOOD
SCOTT	   ANALYST	   3000 	  0 GOOD
KING	   PRESIDENT	   5000 	  0 VERY GOOD
TURNER	   SALESMAN	   1500 	  0 BAD
ADAMS	   CLERK	   1100 	  0 BAD
JAMES	   CLERK	    950 	  0 NULL
FORD	   ANALYST	   3000 	  0 GOOD
MILLER	   CLERK	   1300 	  0 BAD

14 rows selected.

4.2 DECODE函数

  • 语法
DECODE(col|expression,search1,result1
                                         [ , search2,result2, ... , ]                                        
                                         [ , default])

DECODE函数对表达式的解码方式类似于各种语言中使用的IF-THEN-ELSE逻辑。
DECODE函数将表达式与每个搜索值进行比较后对其进行解码。
如果表达式与搜索相同,则返回结果。
如果省略默认值,则返回空值,搜索结果的值不匹配任何值。

SQL> select ename,job,sal,
  2  decode (job,'ANALYST',1.2*SAL,
  3  'MANAGER',1.4*SAL,
  4  'SALESMAN',3*SAL,
  5  SAL)
  6  REVISED_SALARY
  7  from emp;

ENAME	   JOB		    SAL REVISED_SALARY
---------- --------- ---------- --------------
SMITH	   CLERK	    800 	   800
ALLEN	   SALESMAN	   1600 	  4800
WARD	   SALESMAN	   1250 	  3750
JONES	   MANAGER	   2975 	  4165
MARTIN	   SALESMAN	   1250 	  3750
BLAKE	   MANAGER	   2850 	  3990
CLARK	   MANAGER	   2450 	  3430
SCOTT	   ANALYST	   3000 	  3600
KING	   PRESIDENT	   5000 	  5000
TURNER	   SALESMAN	   1500 	  4500
ADAMS	   CLERK	   1100 	  1100
JAMES	   CLERK	    950 	   950
FORD	   ANALYST	   3000 	  3600
MILLER	   CLERK	   1300 	  1300

14 rows selected.

显示部门20的员工,适用的税率:

SQL> select ename,sal,
  2  decode(trunc(sal/2000,0),
  3  0,'0.00',
  4  1,'0.09',
  5  2,'0.20',
  6  3,'0.30',
  7  4,'0.40',
  8  5,'0.42',
  9  6,'0.44',
 10  '0.45') TAX_RATE
 11  from emp
 12  where deptno = 20;

ENAME		  SAL TAX_
---------- ---------- ----
SMITH		  800 0.00
JONES		 2975 0.09
SCOTT		 3000 0.09
ADAMS		 1100 0.00
FORD		 3000 0.09

5 使用组/分组函数汇总数据

5.1 分组函数

  • 分组函数作用于一组数据,并对一组数据返回一个值。
  • 语法
SELECT group_function(column) , ...
FROM table
[WHERE condition]
[ORDER BY column];

5.1.1 AVG()

平均

5.1.2 SUM()

求和

SQL> select avg(sal),sum(sal),max(sal),min(sal) from emp;

  AVG(SAL)   SUM(SAL)	MAX(SAL)   MIN(SAL)
---------- ---------- ---------- ----------
2073.21429	29025	    5000	800

5.1.3 MAX()/MIN()

可以对数字、字符和日期数据类型使用MAX和MIN函数

SQL> select avg(ename) from emp;
select avg(ename) from emp
           *
ERROR at line 1:
ORA-01722: invalid number


SQL> select avg(hiredate) from emp;
select avg(hiredate) from emp
           *
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected NUMBER got DATE


SQL> select min(hiredate),max(ename) from emp;

MIN(HIRED MAX(ENAME)
--------- ----------
17-DEC-80 WARD

5.1.4 COUNT()统计值

1)count(*)
返回满足select语句条件的表中的行数,包括重复的行和任何列中包含空值的行。如果select语句中包含where子句,count(*)返回满足where子句中条件的行数。

SQL> select count(*) from emp
  2  where deptno = 20;

  COUNT(*)
----------
	 5

count(1)与count(*) 的效果一样的,并添加一列值为1的列

SQL> select count(*) from emp;

  COUNT(*)
----------
	14

SQL> select count(1) from emp;

  COUNT(1)
----------
	14

2)count(expr)
返回非空值的expr的行数

SQL> select count(comm) from emp;

COUNT(COMM)
-----------
	  4

3)count(distinct expr)
返回expr非空且不重复的记录数

SQL> select count(distinct job) from emp;

COUNT(DISTINCTJOB)
------------------
		 5

5.1.5 STDDEV()标准差

5.1.6 VARIANCE()方差

5.2 分组函数与空值

  • 组函数忽略空值
SQL> select avg(comm) from emp;

 AVG(COMM)
----------
       550

  • NVL函数使分组函数不忽略空值
SQL> select avg(nvl(comm,0)) from emp;

AVG(NVL(COMM,0))
----------------
      157.142857

6 GROUP BY子句

  • 将信息分成更小的组
  • 语法:
SELECT column,group_function(column)
FROM table
GROUP BY group_by_expression;
  • 使用group by子句将表中的数据分成若干组。
SQL> select deptno,avg(sal) from emp
  2  group by deptno
  3  order by avg(sal);

    DEPTNO   AVG(SAL)
---------- ----------
	30 1566.66667
	20	 2175
	10 2916.66667

在select列表中所有除组函数以外的,所有列都应该包含在group by子句中。(只要写在了select里,就要写在group by里。)

SQL> select job,avg(sal) from emp
  2  where job in ('MANAGER','SALESMAN')
  3  group by job
  4  order by avg(sal);

JOB	    AVG(SAL)
--------- ----------
SALESMAN	1400
MANAGER   2758.33333
  • 多列分组

SQL> select deptno,job,sum(sal) from emp
  2  group by deptno,job
  3  order by deptno;

    DEPTNO JOB	       SUM(SAL)
---------- --------- ----------
	10 CLERK	   1300
	10 MANAGER	   2450
	10 PRESIDENT	   5000
	20 ANALYST	   6000
	20 CLERK	   1900
	20 MANAGER	   2975
	30 CLERK	    950
	30 MANAGER	   2850
	30 SALESMAN	   5600

9 rows selected.

  • 非法使用组函数
    select列表中的列或表达式,未包含在组函数中的列,都必须包含于group by子句中。
    不能使用where子句过滤组。
    可以使用having子句过滤组。

7 HAVING子句

  • 过滤分组
  • 功能:
    1)行已经被分组
    2)使用了分组函数
    3)满足having子句中条件的分组将被显示
SQL> select avg(sal) m,job from emp 
  2  group by job
  3  having avg(sal) >= 3000
  4  order by m;

	 M JOB
---------- ---------
      3000 ANALYST
      5000 PRESIDENT

SQL> select deptno ,max(sal) from emp
  2  group by deptno
  3  having max(sal) >4000;

    DEPTNO   MAX(SAL)
---------- ----------
	10	 5000

看表里的部分数据:where
看结果集里的数据:having 一般会跟着group

8 嵌套组函数

  • 语法
SELECT column,group_function
FROM table
[WHERE condition]
[GROUP BY group_by_expression]
[HAVING group_condition]
[ORDER BY column];
  • 显示平均工资的最大值
SQL> select max(avg(sal)) ma from emp
  2  group by deptno;

	MA
----------
2916.66667

不能写部门

SQL> select max(avg(sal)) ma,deptno from emp
  2  group by deptno;
select max(avg(sal)) ma,deptno from emp
                        *
ERROR at line 1:
ORA-00937: not a single-group group function

你可能感兴趣的:(Oracle)