查询在业务开发中非常常见,几乎 80% 的业务都和查询有关。
2.1 基础查询
语法:
select 查询列表from 表名;
分析:
- 查询列表可以是:表中的字段、常量值、表达式、函数
- 查询的结果是 一个虚拟的表格
实际应用:
- 字段:工作中使用到的最多的就是各种各样的查询,字段当然是主体。需要查表中的哪一列数据就将相应的列放入查询列表中
- 常量值:有时候前端需要展示一些固定的值,比如订单待处理页面的订单的状态列都是待处理,此时可以在列中增加一个 “待处理”的字符串常量。
- 表达式,表达式通常是对某一个字段进行处理之后返回它的值,比如合计列,用来合计某些列的总数数,就可以在查询列表中使用加和表达式。
- 函数:MySQL 中内置了一些函数,可以对单列或者是多列进行处理,返回值则会当成一个新的列返回
示例1:查询单个列
SELECT last_nameFROM employees;
示例2:查询多个列
SELECT last_name,salary,emailFROM employees;
实例3:查询全部字段
# 方式一:SELECTfirst_name,email,phone_number,job_id,salary,commission_pct,manager_id,department_id,hiredateFROM employees;# 方式二SELECT *FROM employees;
注意:方式二非常不建议在实际开发中使用,具体原因可以去百度,记住即可。
实例4:查询常量值
SELECT 10;SELECT 'john';
实例5:查询表达式
SELECT 100*98;
实例6:查询函数
SELECT VERSION();
2.2 条件查询
数据库表一般包含大量的数据,很少需要检索表中的所有行。通常会根据特定操作或者报告的需要提取表数据的子集。
语法:
SELECT 查询列表FROM 表名WHERE 筛选条件;
where 操作符:
| 操作符 | 说明 |
|---|---|
| > | 大于 |
| < | 小于 |
| = | 等于 |
| <=> | 安全等于 |
| >= | 大于等于 |
| <= | 小于等于 |
| <> | 不等于 |
| IS NULL | 判空 |
| IS NOT NULL | 判非空 |
| BETWEEN AND | 指定区间 |
| IN | 判定是否在集合中 |
| AND | 与 |
| OR | 或 |
| NOT | 非 |
| LIKE | 模糊查询 |
实例1:查询工资大于 12000 的员工
select *FROM employeeswhere salary>12000;
实例2:查询部门编号不等于 90 的员工名和部门编号
select last_name,department_idFROM employeesWHERE department_id <> 90;
实例3:工资在 10000 到 20000 之间的员工名、工资以及奖金
SELECT last_name,salary,commission_pctFROM employeesWHERE salary>=10000 AND salary<=20000;# 等价于SELECT last_name,salary,commission_pctFROM employeesWHERE salary BETWEEN 10000 AND 20000;
在使用 BETWEEN AND 时要注意:
- column BETWEEN a AND b 关键字等价于 column >= a AND column <= b 用数学语言来说就是 a 和 b 的闭区间(包含边界值)。
- a 和 b 的位置不能替换,不然会查不到结果
- a 和 b 的类型必须一致,或者可以自动转换
实例4:查询部门编号不是在90到110之间,或者工资高于15000的员工信息
SELECT *FROM employeesWHERE employee_id < 90 OR employee_id >110OR salary > 15000;
实例5:查询员工中包含字符 a 的员工
SELECT *FROM employeeswhere last_name LIKE '%a%';
LIKE 用于模糊查询,% 表示任意多个任意字符
实例6:查询员工名中第二个字符为 a 的员工
SELECT *FROM employeeswhere last_name LIKE '_a%';
“_” 表示占位符,表示一个任意符号。
实例7:查询员工姓名中第二个为 _ 员工
# 使用转义字符SELECT last_nameFROM employeeswhere last_name LIKE '_\_%';# 自定义转义符SELECT last_nameFROM employeesWHERE last_name LIKE '_$_%' ESCAPE '$';
对于特殊符号,可以使用默认的转义字符
\进行转义,也可以使用 ESCAPE 关键字自定义自己的转义符号
实例8: 查询员工的工种编号是否是 IT_PROGE,AD_VP,AD_PRES 中的一个员工名和公众编号
SELECT last_name,job_idFROM employeesWHERE job_id IN ('IT_PROGE','AD_VP','AD_PRES');
- 使用in提高语句的简洁度,in可以和多个等值判断替换 x in(1,2,3)可以替换成 x=1 or x=2 or x=3
- in列表中不会匹配通配符,因为 in和等值判断等效,所以 x = %a%这种等式无法成立,因为 = 是确认条件,不是模糊条件
- in列表的值类型必须一致或者兼容
实例9:查询没有奖金的员工名和奖金率
SELECT last_name,commission_pctFROM employeesWHERE commission_pct IS NULL;
实例10:查询有奖金员工的员工名和奖金率
SELECT last_name,commission_pctFROM employeesWHERE commission_pct IS NOT NULL;
= 和 <> 不能用于判断 NULL 值,IS NULL 或 IS NOT NULL 可以判断 NULL 值,但是 IS 不能单独使用
实例11:查询没有奖金的员工共名和奖金率
SELECT last_name,commission_pctFROM employeesWHERE commission_pct <=> NULL;
实例12:查询奖金率为 0.4 的员工名和奖金率
SELECT last_name,commission_pctFROM employeesWHERE commission_pct <=> 0.4;
<=> 符号既可以用来判断 null 值,也可以用来判断普通的数值类型。但是它的可读性比较差。
经典面试题:限免两条语句的查询结果是否一样?
SELECT * FROM employees; #共107条SELECT * FROM employees WHERE commission_pct LIKE "%%" AND last_name LIKE "%%";#35条
不一样,%%不匹配空值
2.3 排序查询
其实,检索出的数据并不是以纯粹的随机顺序显示的。如果不排序,数据一般将以它在底层中出现的顺序显示。这可以是数据最初添加到表中的数据。但是,如果数据后来进行过更新或删除,则此顺序将会收到 MySQL 重用回收存储空间的影响。因此,如果不明确控制的话,不能(也不应该)一来该排序顺序。关系数据库设计理论认为,如果明确规定排序顺序,则不应该假定检索出的数据的顺序有意义。所以为了明确地对 SELECT 语句,可使用 ORDER BY 子句 ,ORDER BY 子句取一个或多个列的名字,据此对输出进行排序。
子句的概念:SQL语句由子句构成,有些子句是必须的,而有的有的是可选的。一个子句通常由一个关键字和所提供的数据组成。例如 SELECT 子句和 FROM 子句。
语法:
SELECT 条件列表FROM 表名[where 筛选条件]order by 排序条件 [asc|desc]
默认是 asc 升序排序
实例1:查询员工工资,要求工资从低到高排序
SELECT salaryFROM employeesORDER BY salary ASC;
实例2:查询员工工资,要求工资从高到低排序
SELECT salaryFROM employeesORDER BY salary DESC;
实例3:按年薪的高低显示员工的信息和年薪
SELECT first_name,salary*12*(1+IFNULL(commission_pct,0)) 年薪FROM employeesORDER BY salary*12*(1+IFNULL(commission_pct,0));SELECT first_name,salary*12*(1+IFNULL(commission_pct,0)) 年薪FROM employeesORDER BY 年薪;
可以通过表达式,或者是表达式的别名进行排序
实例4:按照姓名的长度显示员工的姓名和工资
SELECT first_name,LENGTH(first_name)FROM employeesORDER BY LENGTH(first_name);
按照函数的返回值对数据进行排序
实例5:查询员工信息,要求先按工资升序排序,再按员工编号降序排序
SELECT *FROM employeesORDER BY salary ASC,employee_id DESC;
总结:
- asc 代表的是升序,desc代表的是降序,如果不写,则默认是升序
- order by 子句可以支持单个字段、多个字段、表达式、函数、别名
- order 子句一般放在查询语句的最后面,limit 子句除外。
2.4 分组查询
分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。
语法:SELECT 查询列表FROM TABLE[WHERE CONDITION]GROUP BY 分组字段[ORDER BY column]
特点:
- 查询列表最好是分组函数和 group by 后面的字段(不会报错,但是逻辑上显然是无效的查询)
- GROUP BY 子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据提供更细致的控制。比如对 A,B 两个字段进行分组,那么 A1,B1 和 A1,B2 就成了两个分组,也就是嵌套分组的意思,A 分组中继续对 B 进行分组。
- GROUP BY 子句中列出的梅个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在 SELECT 中使用表达式,则必须在 GROUP BY 子句中指定相同的表达式,不能使用别名。
- 如果分组中具有 NULL 值,则 NULL 将作为一个分组返回。如果列中有多行 NULL 值,它们将被分为一组。
- GROUP BY 子句必须出现在 WHERE 子句之后,ORDER BY 子句之前
实例1:查询邮箱中包含 a 字符的,每个部门的平均工资
SELECT AVG(salary),department_idFROM employees#WHERE INSTR(email,'a') <> 0WHERE email LIKE '%a%'GROUP BY department_id;
实例2:查询每个领导手下有奖金的员工的最高工资
select MAX(salary),manager_idFROM employeesWHERE commission_pct IS NOT NULLGROUP BY manager_id;
having 关键字
除了能用 GROUP BY 分组数据外,MySQL 还允许过滤分组,规定包括哪些分组,排除哪些分组。WHERE 语句只是针对行进行过滤,而不能对组进行过滤。如果要对分组进行过滤,就需要使用 HAVING 关键字。用法和 WHERE 一样,唯一的区别是 WHERE 过滤行,而 HAVING 过滤组。
实例1:查询员工数大于 2 的部分
SELECT department_id,COUNT(*)FROM employeesGROUP BY department_idHAVING COUNT(*)>2;
实例2:查询每个工种有奖金的员工的最高工资,并且只显示最高工资大于 12000 的工种
SELECT MAX(salary),job_idFROM employeesGROUP BY job_idHAVING MAX(salary)>12000;
实例3:查询临到编码大于 102 的,手下员工的最低工资大于 5000 的最低工资
SELECT manager_id,MIN(salary) 最低工资FROM employeesWHERE manager_id >102GROUP BY manager_idHAVING 最低工资>5000;
manager_id > 102 这句,既可以使用 WHERE 来筛选,又可以使用 HAVING 语句来筛选。这是因为分组规则就是 manager_id,虽然 WHERE 是针对行来筛选的,但是对于分组来说效果是一样的,按照 manager_id 进行分组时,组内的所有 manager_id 都是一样的。所以 对于分组字段的筛选,WHERE 和 HAVING 基本一致。但是还是建议放在 WHERE 子句中,性能会更高一点,避免先对数据进行分组,又筛选掉一部分组。
实例4:按员工姓名的长度进行分组,查询每一组的员工的个数,筛选员工个数大于 5 的组。
SELECT COUNT(*),LENGTH(last_name)FROM employeesGROUP BY LENGTH(last_name)HAVING COUNT(*) > 5;
实例5:查询每个部门每个工种的员工的基本工资
SELECT AVG(salary),department_id,job_idFROM employeesGROUP BY department_id,job_id;
分组字段部分先后,从两个分组里面找交集
案例6:查询每个工种的员工的平均工资,并按照平均工资排序
SELECT AVG(salary),department_id,job_idFROM employeesGROUP BY department_id,job_idORDER BY AVG(salary)
总结:
- 分组函数做条件必须放在 having 子句中
- 能用分组前筛选的,就有限考虑使用分组前筛选
- group by 子句支持单个字段分组,多个个字段分组(多个字段之间用逗号隔开,没有顺序之分),也可以支持表达式或者是函数,但是用的较少。
补充知识:
本章节的主要知识有:
查询获得的结果是一张二维表,类似于 excel,表头就是我们查询列表中的列的名字,但是通常字段的名字并不利于我们理解和使用,因此我们也可以对表头进行自定义
语法:
SELECT 查询字段1 AS 别名1,查询字段2 AS 别名2;
分析:
- 查询出来的二维表的表头是 别名1,别名2。而不是原先的 查询字段1,查询字段2。
实际应用:
- 实际开发中经常涉及到数据的封装,即把从数据库中查出来的数据封装到 POJO对象中。要想封装到对应的字段中,就必须有映射关系。一般来说,数据库中字段的名字和对象中 setter 方法是一样的。但是有时候因为业务不同,命名并不一致,此时也经常会使用到起别名,使得表的字段名和Java对象相对应。
实例:
# 方式一: AS 后面跟 别名SELECT 100%99 AS 结果;SELECT last_name AS 姓,first_name AS 名FROM employees;# 方式二:省略 ASSELECT last_name 姓,first_name 名FROM employees;# 别名和关键字重复SELECT salary AS "select"from employees;
Tis:建议规范书写 sql 时,将所有的关键字大写,而所有的表和列名小写
2. 去重
查询时不想显示重复的列,可以使用 DISTINCT 关键字修饰列,就不会出现重复的列了。
语法
select DISTINCT 查询列表from 表名;
注意:
DISTINCT 关键字应用于所有列而不仅是前置它的列。如果给出多个列,那么只有当这多个列的所有值都相同才会去重
3. 正则表达式
语法
SELECT 查询列表FROM 表名WHERE 字段 REGEXP '正则表达式规则';
- REGEXP 在列值内进行匹配,如果被匹配的文本在列值中出现, REGEXP 将会找到它,相应的行将被返回。(比如 REGEXP ‘1000’,凡是包含 1000 的列值都会被返回)。
- MySQL中的正则表达式匹配不区分大小写。如果要区分大小写,可使用 BINARY 关键字,如 WHERE prod_name REGEXP BINARY ‘JetPack .000’
进行OR匹配
为搜索两个串之一(或者为这个串,或者为另一个串),使用 | ,如下所示:
SELECT prod_nameFROM productsWHERE prod_name REGEXP '1000|2000'ORDER BY prod_name;
语句中使用了正则表达式
1000|2000。|为正则表达式的OR操作符。它表示匹配其中之一,因此 1000 和 2000 都匹配并返回。
使用 | 从功能上类似于在 SELECT 语句中使用 OR 语句,多个 OR 条件可并入单个正则表达式。
SELECT prod_nameFROM productsWHERE prod_name REGEXP '1000|2000|3000|4000'ORDER BY prod_name;
匹配几个字符之一
使用 [123] 表示取中括号中的任意一个
SELECT prod_nameFROM productsWHERE prod_name REGEXP '[123] Ton'ORDER by prod_name;
匹配范围
集合可用来定义要匹配的一个或多个字符,例如,下面的集合将匹配数字0到9:
[123456789]
但是为了简化这种类型的集合,可使用 - 来定义一分范围。下面的式子功能上等同于上述数字列表:
[0-9]
范围不限于完整的集合,[1-3] 和 [6-9] 也是合法范围。此外范围不一定只是数值的,[a-z] 匹配任意字母字符。
匹配特殊字符
正则表达式语言具有特定含义的特殊字符构成。如果我们要匹配的正好就是这些特殊符号本身,可以以 \\ 为前导对这些特殊符号进行转义
匹配字符类
存在找出你自己常用的数字、所有字母字符、所有字母字符或所有数字字母字符等的匹配。为了更方便工作,可以使用预定义的字符集,称为字符类(character class)。
匹配多个实例
目前位置,所有正则表达式都试图匹配单次出现。如果存在一个匹配,该行被检索出来,如果不存在,检索不出任何行。但有时需要对匹配的数目进行更强的控制。例如,你可能需要寻找所有的数,不管数中包含多少数字,或者你可能想寻找一个单词并且还能够适应一个尾随的 s (如果存在),等等。
这可以用表 9-3 列出的正则表达式重复元字符来完成
定位符
目前位置的所有例子都是匹配一个串中任意位置的文本。为了匹配特定位置的文本,需要使用定位符。
**^**的双重用处^在集合中,用它来否定集合 不在集合中,用来指串的开始处。 使 REGEXP 起类似 LIKE 的作用 本章前面说过, LIKE 和 REGEXP的不同在于, LIKE 匹配整个串而 REGEXP 匹配子串。利用定位符,通过用 ^ 开始每个表达式,用 $ 结束每个表达式,可以使REGEXP 的作用与 LIKE 一样。
补充:
- concat():字符串连接函数(字符串1,字符串2,…)
- ifnull():如果某字段或表达式为null,则返回特定的值,否则返回原本的值。ifnull(需要本段的字段,如果为null要返回的值)
- isnull():判断字段是否为null,如果为null返回1,如果不为null返回0.在数据库中0代表false,1代表true
- WHERE 子句通常用来过滤数据,在实际应用中,也可以在程序中进行过滤,不过这种方式并不让人满意,因为本来该由数据库处理的数据却让应用程序来处理,一方面影响了程序的性能,另一方面多余的数据也占用了带宽,对资源造成一定的浪费。并且在有索引的情况下,速度是远远高于应用程序的。
注意:
- SQL(像多数语言一样)在处理 OR 操作符前,优先处理 AND 操
作符。例如 condition1 OR condition2 AND condition3 会优先执行 condition2 AND condition3
- MySQL 支持使用NOT对IN、BETWEEN和EXISTS子句取反。
- 不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符(因为通配符性能较低)
- 在确实需要使用通配符时,除非绝非必要,否则不要把它们用在搜索模式的开始处。把通配符置于搜索模式的开始,搜索起来时最慢的(也就是尽量把模糊查询的子句放在最后面)
4. MySQL 常用函数
MySQL 中的函数类似于 Java 中的方法,将一组逻辑语句封装在一起,对外暴露方法名。隐藏了实现细节,提高代码的重用性。
4.1 单行函数
4.1.1 字符处理函数
length() :获取参数值的字节个数
SELECT LENGTH('john'); # 4个字节SELECT LENGTH("我爱你中国");# 15 个字节
concat:拼接多个字符
SELECTCONCAT(last_name,'_',first_name)FROMemployees;
upper、lower 将字符全部转换为大写或者是小写
# upper、lowerSELECT UPPER('jhon');SELECT LOWER('ABC');## 案例:将姓变大写,名变小写,然后拼接SELECT CONCAT(UPPER(last_name),'_',LOWER(first_name))FROM employees;
substr、substring通过字符下标获取对应的子串
SELECT SUBSTR('文天祥人生自古谁无死',1,3); # 文天祥SELECT SUBSTRING('民族英雄文天祥',5); #文天祥
注意在mysql数据库中,索引是从1开始的,这个函数可以只提供一个参数,表示从这个参数开始到字符结束的位置。也可以给定两个参数,例如给a,b:那么从a(包含a)到b(也包含b)下标的子串。
instr: 获取字符中,字串第一次出现的第一个字符的下标。如果没有则返回0
SELECT INSTR("hello","ll");#3
trim:去除首尾两个的空格,或者是指定的值
## trim去除空格select LENGTH(" 1234567 "),LENGTH(TRIM(" 1234567 "));## 去除字符串首部和尾部出现的aSELECT TRIM('a' FROM "aaaaaaaaaaasksksaakkaaaaaaaa");
lpad 和 rpad 用指定的字符将字符串填充到指定长度
## LPAD(str,len,padstr)SELECT LPAD("i love you",20,"-+")## 如果填充长度比那个字符串本来的长度还小,则将字符串超过的部分删除SELECT LPAD("i love you",3,"-+") # i l## RPAD(str,len,padstr)SELECT RPAD("dpttt",2,"k") #dp
replace(字符串,被替代的部分,用来替代的部分)
##REPLACE(str,from_str,to_str)SELECT REPLACE("今天的天气很不错","今天","明天");
left(str,len) 返回串左边的字符
SELECT LEFT("中文字符",2);#中文
right(str,len) 返回串右边的字符
SELECT RIGHT("中文字符",2)#字符
locate(substr,str) 找出串的一个子串
SELECT LOCATE("ll","hello");#3
和 locate 效果一样
LTrim() 去掉串左边的空格
select LTRIM(" hello ");#hello
Rtrim() 去掉串右边的的空格
select RTRIM(" hello ");# hello
Soundex() 返回串的 SOUNDEX 值
Soundex 是一个将任何文本串转换为描述其语音表示的字母数字模式的算法。SOUNDEX 考虑了类似的发音字符串和音节,使得能对串进行发音比较而不是字母比较。虽然 SOUNDEX 不是SQL的概念,但 MySQL 提供了对 SOUNDEX 的支持。
4.1.2 数学函数
round 四舍五入
## ROUND(X)SELECT ROUND(1.47);#1SELECT ROUND(-1.45);#1
只针对小数点后一位进行四舍五入
ceil 向上取整
## ROUND(X)SELECT CEIL(1.001);#2SELECT CEIL(-1.001);#-1
返回大于等于输入值的最小整数
floor 向下取整
## FLOOR(X)SELECT FLOOR(1.999);#1SELECT FLOOR(-1.999);#-2
truncate 截断,小数点后保存几位
## 截断SELECT TRUNCATE(10.999,2);#10.99
直接截断不进行四舍五入
mod取余
## MOD(N,M)SELECT MOD(10,3);#1SELECT MOD(-10,3);#-1SELECT MOD(10,-3);#1
取余公式:a%b=a-a/bb;在Java中,整数除以整数就是整数。所以 10-10/33=10-3*3=10-9; 为什么可以这么算? 这是因为,余数就是被除数减去除数的最大整数倍得到的结果。 速记:取余的结果的正负只和被余数的正负有关。
4.1.3 日期函数
日期函数的意思是,输入的参数类型为日期类型,针对日期类型去处理
now():返回当前系统日期+时间
curtime:返回当前时间不包含日期
获取一个日期中的 年、月、日、时、分、秒
## 获取年
SELECT YEAR(NOW()) 年;#2021
SELECT YEAR('199606-26');#NULL
SELECT YEAR('1996-0-626');#NULL
SELECT YEAR('1996 06-26');#NULL
SELECT YEAR('1996 06 26');#NULL
SELECT YEAR('1996-06-26');#1996
SELECT YEAR('1996&06-26');#1996
SELECT YEAR('1996^06-26');#1996
##获取月
SELECT MONTH('1996-06&26');#6
##获取日
SELECT DAY('1996-06&26');#26
##获取时
SELECT HOUR('1992-04-03 22:30:59');#22
## 获取分
SELECT MINUTE('1992-04-03 22:30:59');#30
## 获取秒
SELECT SECOND('1992-04-03 22:30:59');#59
str_to_date:将日期格式的字符串转换成指定格式的日期
date_format:将日期装换成字符串

格式转换表
# str-to_date()按照指定的格式解析
SELECT STR_TO_DATE('06-26-1996','%m-%d-%Y');#1996-06-26
# 这个函数的意思是,将字符串按照指定的格式解析后,返回一个数据库格式的日期字符串,即年-月-日这种格式
# date_format
SELECT DATE_FORMAT('1996-06-26','%m-%d-%Y');#06-26-1996
从这两个函数可以看出来,其实数据库中所谓的日期,本质就是字符串,但是这个字符串必须符合 年-月-日 00:00:00 这样的格式,不然就是字符串,而不是日期。随意这两个方法本质上是在将字符串中的字符的顺序进行改变。
注意:
如果要的是日期,请使用 Date() :如果你想要的仅是日期,
则使用 Date() 是一个良好的习惯,即使你知道相应的列只包
含日期也是如此。这样,如果由于某种原因表中以后有日期和
时间值,你的SQL代码也不用改变。当然,也存在一个 Time()
函数,在你只想要时间时应该使用它。
Date() 和 Time() 都是在MySQL 4.1.1中第一次引入的。
技巧:
如果你想检索出 2005 年 9 月下的所有订单,怎么办?简单的相等测试不行,因为他也要匹配月份中的天数。有几种解决办法,其中之一如下所示
还有另一种办法(一种不需要记住每个月中有多少天或不需要操心闰年2月的办法):
4.1.4 其他函数
## 查看数据库的版本
SELECT VERSION();
## 查看当前数据库
SELECT DATABASE();
## 查看当前用户
SELECT USER();
4.1.5 流程控制函数
## if ELSE
SELECT IF(10>5,"10大于5","10不大于5");
/**
case 要判断的字段或者表达式
WHEN 常量1 THEN 要显示的值1 或语句1;
WHEN 常量2 THEN 要显示的值2 或语句2;
……
ELSE 要显示的值n或语句n
END
一般使用需要搭配select进行使用,这时候 then后面只能跟对应的值,而不能是语句
但是如果是用在存储过程当中,就可以单独使用该语句,then后面就可以跟语句
如果是语句,就要加分号,如果是值就不能加分号
*/
select salary 原始工资 ,department_id,
CASE department_id
WHEN 30 THEN salary*1.1
WHEN 40 THEN salary*1.2
WHEN 50 THEN salary*1.3
ELSE salary
END AS 新工资
FROM employees;
## 案例,查询员工的工资情况
/*
如果工资>20000,显示A级别
如果工资>15000,显示B级别
如果工资>10000,显示c级别
否则,显示D级别
*/
SELECT salary,
CASE
WHEN salary>20000 THEN 'A'
WHEN salary>15000 THEN 'B'
WHEN salary>10000 THEN 'C'
ELSE 'D'
END as 工资级别
FROM employees;
第一行 department_id 后面的逗号不能少。case 是一个整体
单行函数总结
字符函数:
length,concat,substr,instr,trim,upper,lower,lpad,rpad,replace
数学函数:
round,ceil,floor,truncate,mod
日期函数:
now,curdate,curtime,year,month,monthname,day,hour,minute,second,str_to_date,date_format
其它函数:version,datebase,user
控制函数
if,case
4.2 分组函数
功能:用作统计使用,又称为聚合函数,或统计函数,或组函数 分类:sum 求和,avg平均值、max最大值、min最小值、count计算个数
# 简单的使用
SELECT SUM(salary) FROM employees;
SELECT avg(salary) FROM employees;
SELECT MIN(salary) FROM employees;
SELECT COUNT(salary) FROM employees;
SELECT SUM(salary) 工资和,AVG(salary) 平均工资 ,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 非空数据的个数
FROM employees;
#2. 参数支持哪些类型
SELECT SUM(last_name),AVG(last_name) FROM employees;# 虽然没有报错,但是没有逻辑意义
SELECT SUM(hiredate),AVG(hiredate) FROM employees;# 日期类型也不能用于统计,没有报错,但是没有意义
SELECT MAX(last_name),MIN(last_name) FROM employees;# 可以排序,自然就有大小之分,根据字典序
SELECT MAX(hiredate),MIN(hiredate) FROM employees;# 根据时间大小
SELECT COUNT(commission_pct) FROM employees;#count只计算非空的行
SELECT COUNT(last_name) FROM employees;
特点:
- sum、avg一般由于处理数值型。
max,min,count可以处理任何类型 - 是否忽略null值
所有的分组函数都是忽略null值的。 - 可以和distinct搭配实现去重的运算
count 函数的详细介绍 ```sql#和distinct搭配去重 SELECT SUM(DISTINCT salary),SUM(salary) FROM employees; SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;count函数的的详细介绍
SELECT COUNT(salary) FROM employees; SELECT COUNT(*) FROM employees; SELECT COUNT(1) FROM employees;
- count函数的参数有上述3中,参数为字段、*、常量值
- count里面可以是多个字段,如果其中的字段都为null,才会忽略这一行,只要有一个字段的值不为null,就不是null
- count里面 * 表示所有的字段,因此在计算行数时,直接+1,不会进行判断,因为没有一行所有的字段都为null。
- count里面 1 或者是 '字符串' 相当于给每一行添加一个字段,字段的值为count里面的值,因此不会忽略任意一行
- 效率:count(*)和count(1)的效率相同,比 count(字段)要高,因为count(字段)会进行判断,看字段值是否为空。
- 一般使用 count(*) 来查询行数。
**和分组函数以同查询的字段有限制**
```sql
SELECT AVG(salary) ,employee_id FROM employees;# 虽然没有错,但是没有意义
和分组函数一同查询的字段要求是 group by 后的字段
练习
# 1.查询公司员工工资的最大值,最小值,平均值,总和
SELECT MAX(salary),MIN(salary),ROUND(AVG(salary),2),SUM(salary)
FROM employees;
# 2. 查询员工表中的最大入职时间和最小入职时间的相差天数
#SELECT YEAR(MAX(hiredate))-YEAR(MIN(hiredate))*365+MONTH() FROM employees;
# 日期相减函数
SELECT DATEDIFF(MAX(hiredate),MIN(hiredate)) FROM employees;
# 3. 查询部门编号为90的员工的个数
SELECT COUNT(*) FROM employees where department_id = 90;
注意:
函数没有SQL的可以执行强 多数 SQL 语句是可以执的,在SQL实现之间有差异时,这些差异通常不那么难处理。而函数的可以执行却不强。几乎每种主要的 DBMS 的实现都支持其他实现不支持的函数,而且有时差异还很大。
