欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL6天学习笔记 —— day02

程序员文章站 2022-05-30 13:17:56
...


5. DQL语言的学习

5.1 基础查询

-- 进阶1:基础查询
/*
语法:
select 查询列表 from 表名;

类似于: System.out.println(要打印的东西)

特点:
	1、查询列表可以是: 表中的字段、常量值、表达式、函数
	2、查询的结果是一个虚拟的表格(临时存在的)
*/

-- 指定使用的数据库
USE myemployees;

-- 1. 查询表中的单个字段
SELECT last_name FROM employees;

-- 2.查询表中的多个字段
SELECT last_name,salary,email FROM employees;

-- 3.查询表中的所有字段
-- 方式一:
SELECT 
    `employee_id`,
    `first_name`,
    `last_name`,
    `phone_number`,
    `job_id`,
    `salary`,
    `commission_pct`,
    `manager_id`,
    `department_id`,
    `hiredate` 
FROM
    employees;
-- 注意:``表示的是里面的内容是一个字段,而不是关键字,建议每次查询字段都要加上这个
		
-- 方式二:
SELECT * FROM employees;

-- 4.查询常量值
-- 注意:字符型和日期型的常量值必须用单引号引起来,数值型不需要
SELECT 100;

-- 5.查询表达式
SELECT 100%98;

-- 6.查询函数
SELECT VERSION();

-- 7.为字段起别名
/*
1、便于理解
2、如果要查询的字段有重名的情况,使用别名可以区分开来
*/
-- 方式一:使用as
SELECT 100%98 AS 结果;
SELECT last_name AS,first_name ASFROM employees;

-- 方式二:使用空格
SELECT last_name 姓,first_name 名 FROM employees;

-- 案例:查询salary,显示结果为 out put
-- 注意:如果起的别名是关键字,建议使用双引号括起来
SELECT salary AS "out put" FROM employees;

-- 8.去重
-- 案例:查询员工表中涉及到的所有的部门编号
SELECT DISTINCT department_id FROM employees;
-- 根据a和b两个字段去重的
SELECT DISTINCT a,b FROM 表名;

-- 9.+号的作用
/*
java中的+号:
1、运算符,两个操作数都为数值型
2、连接符,只要有一个操作数为字符串

mysql中的+号:
仅仅只有一个功能:运算符

select 100+90; 两个操作数都为数值型,则做加法运算
select '123'+90;只要其中一方为字符型,试图将字符型数值转换成数值型
								如果转换成功,则继续做加法运算
select 'john'+90;	如果转换失败,则将字符型数值转换成0

select null+10; 只要其中一方为null,则结果肯定为null
*/

-- 10.concat函数
/*
1.作用:拼接字符
2.语法格式:select concat(字符1,字符2,...)
*/
-- 案例:查询员工名和姓连接成一个字段,并显示为 姓名
SELECT CONCAT('a','b','c') AS 结果;

SELECT 
	CONCAT(last_name,first_name) AS 姓名
FROM
	employees;
	
-- 11.isnull函数
/*
1.作用:判断某字段或表达式是否为null,如果是null,返回1,否则返回0
2.语法格式:select isnull(字段名) from 表名;
*/
SELECT
	ISNULL( commission_pct ),
	commission_pct 
FROM
	employees;

5.1.1 基础查询练习

-- 1.显示表departments的结构,并查询其中的全部数据
DESC departments;
SELECT * FROM `departments`;

-- 2.显示出表employees中的全部job_id(不能重复)
SELECT DISTINCT job_id FROM employees;

-- 3.显示出表employees的全部列,各个列之间用逗号连接,列头显示成OUT_PUT
-- IFNULL函数
/*
1.作用:判断某字段或表达式是否为null,如果为null,就返回指定的值,否则返回原本的值
2.语法格式: select IFNULL(字段名,指定的值) from 表名;
*/
SELECT 
	IFNULL(commission_pct,0) AS 奖金率,
	commission_pct
FROM 
	employees;
#-------------------------------------------
SELECT
	CONCAT(`first_name`,',',`last_name`,',',`job_id`,',',IFNULL(commission_pct,0)) AS out_put
FROM
	employees;

5.2 条件查询

-- 进阶2:条件查询
/*
语法:
		select 
			查询列表
		from
			表名
		where
			筛选条件;
			
分类:
		一、按条件表达式筛选
		简单条件运算符:>   <   =   !=   <>   >=   <=
		注意:<>表示的是不等于,使用不等于的话建议用这个
		
		二、按逻辑表达式筛选
		逻辑运算符:
							&&       ||       !
							and      or				not
		作用:用于连接条件表达式
		说明:
				&&和and:两个条件都为true,结果为true,反之为false
				||或or: 只要有一个条件为true,结果为true,反之为false
				!或not: 如果连接的条件本身为false,结果为true,反之为false
		
		三、模糊查询
							like
							between and
							in
							is null		
*/

-- 1.按条件表达式筛选
-- 案例1:查询员工工资>12000的员工信息
SELECT 
	*
FROM
	employees
WHERE
	salary>12000;

-- 案例2:查询部门编号不等于90号的员工名和部门编号
SELECT 
	last_name,
	department_id
FROM
	employees
WHERE
	department_id<>90;
	
-- 案例3:查询员工号为 176 的员工的姓名和部门号和年薪
SELECT
	last_name,
	department_id,
	salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) AS 年薪 
FROM
	employees;
	
-- 2.按逻辑表达式筛选
-- 案例1:查询工资在10000到20000之间的员工名、工资以及奖金
SELECT
	last_name,
	salary,
	commission_pct
FROM
	employees
WHERE
	salary>=10000 AND salary<=20000;

-- 案例2:查询部门编号不是在90到110之间,或者工资高于15000的员工信息
-- 方式一:
SELECT
	*
FROM
	employees
WHERE
	NOT(department_id>=90 AND department_id<=110) OR salary>15000;
	
-- 方式二:
SELECT
	* 
FROM
	employees 
WHERE
	department_id < 90 OR department_id > 110 
	OR salary > 15000
	
-- 3.模糊查询

-- 3.1 like
/*
		特点:
		①一般和通配符搭配使用,可以判断字符型或数值型
			通配符:
			% 任意多个字符,包含0个字符
			_ 任意单个字符
*/
-- 案例1:查询员工名中包含字符a的员工信息
SELECT
	* 
FROM
	employees 
WHERE
	last_name LIKE '%a%';

-- 案例2:查询员工名中第三个字符为n,第五个字符为l的员工名和工资
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	last_name LIKE '__n_l%';
	
-- 案例3:查询员工名中第二个字符为_的员工名
-- 方式一:使用转义字符 "\_"
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	last_name LIKE '_\_%';

-- 方式二:使用ESCAPE '任意字符',将这个字符当做转义字符使用(推荐使用)
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	last_name LIKE '_$_%' ESCAPE '$';
	
-- 案例4:查询部门编号是1开头的,并且是3位数的员工信息
SELECT
	* 
FROM
	employees 
WHERE
	department_id LIKE '1__';
	
-- 3.2 between and
/*
①使用between and 可以提高语句的简洁度
②包含临界值
③两个临界值不要调换顺序
*/
-- 案例1:查询员工编号在100到120之间的员工信息
-- 方式一:
SELECT
	* 
FROM
	employees 
WHERE
	employee_id >= 100 
	AND employee_id <= 120;

-- 方式二:推荐使用
SELECT
	* 
FROM
	employees 
WHERE
	employee_id BETWEEN 100 AND 120;

-- 3.3 in
/*
含义:判断某字段的值是否属于in列表中的某一项
特点:
	①使用in提高语句简洁度
	②in列表的值类型必须一致或兼容(同一字段)
	③in列表中不支持通配符
*/
-- 案例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个的员工名和工种编号
-- 方式一:
SELECT
	last_name,
	job_id
FROM
	employees
WHERE
	job_id = 'IT_PROT' OR job_id = 'AD_VP' OR JOB_ID ='AD_PRES';
	

-- 方式二:推荐使用
SELECT
	last_name,
	job_id
FROM
	employees
WHERE
	job_id IN( 'IT_PROT' ,'AD_VP','AD_PRES');
	
-- 3.4 is null
/*
	!=或<>不能用于判断null值
	is null或is not null 可以判断null值
*/
-- 案例1:查询没有奖金的员工名和奖金率
SELECT
	last_name,
	commission_pct
FROM
	employees
WHERE
	commission_pct IS NULL;

-- 案例2:查询有奖金的员工名和奖金率
SELECT
	last_name,
	commission_pct
FROM
	employees
WHERE
	commission_pct IS NOT NULL;

-- 错误写法,执行报错
SELECT
	last_name,
	commission_pct
FROM
	employees

WHERE 
	salary IS 12000;

-- 3.5 安全等于 <=>
/*
						isnull和<=>的区别?
IS NULL:仅仅可以判断NULL值,可读性较高,建议使用
 <=>   :既可以判断NULL值,又可以判断普通的数值,可读性较低
*/
-- 案例1:查询没有奖金的员工名和奖金率
SELECT
	last_name,
	commission_pct 
FROM
	employees 
WHERE
	commission_pct <=> NULL;

-- 案例2:查询工资为12000的员工信息
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	salary <=> 12000;

5.2.1 条件查询练习

-- 1.查询工资大于 12000 的员工姓名和工资
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	salary > 12000;

-- 2.查询员工号为 176 的员工的姓名和部门号和年薪
SELECT
	last_name,
	department_id,
	salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) AS 年薪 
FROM
	employees;

-- 3.选择工资不在 5000 到 12000 的员工的姓名和工资
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	NOT ( salary < 5000 AND salary > 12000 );

-- 4.选择在 20 或 50 号部门工作的员工姓名和部门号
SELECT
	last_name,
	department_id 
FROM
	employees 
WHERE
	department_id = 20 
	OR department_id = 50;

-- 5.选择公司中没有管理者的员工姓名及 job_id
SELECT
	last_name,
	job_id 
FROM
	employees 
WHERE
	manager_id IS NULL;

-- 6.选择公司中有奖金的员工姓名,工资和奖金级别
SELECT
	last_name,
	salary,
	commission_pct 
FROM
	employees 
WHERE
	commission_pct IS NOT NULL;

-- 7.选择员工姓名的第三个字母是 a 的员工姓名
SELECT
	last_name 
FROM
	employees 
WHERE
	last_name LIKE '__a%';

-- 8.选择姓名中有字母 a 和 e 的员工姓名
SELECT
	last_name 
FROM
	employees 
WHERE
	last_name LIKE '%a%' 
	AND last_name LIKE '%e%';

-- 9.显示出表 employees 表中 first_name 以 'e'结尾的员工信息
SELECT
	* 
FROM
	employees 
WHERE
	first_name LIKE '%e';

-- 10.显示出表 employees 部门编号在 80-100 之间 的姓名、职位
SELECT
	last_name,
	job_id 
FROM
	employees 
WHERE
	department_id BETWEEN 80 
	AND 100;

-- 11.显示出表 employees 的 manager_id 是 100,101,110 的员工姓名、职位
SELECT
	last_name,
	job_id 
FROM
	employees 
WHERE
	manager_id IN ( 100, 101, 110 );

5.2.2 经典面试题

试问:select * from employees;select * from employees where `commission_pct` like '%%' and `last_name` like '%%';
结果是否一样?并说明原因

回答:如果判断的字段中有null值,结果就是不一样的;而如果判断的字段中没有null值,结果就是一样的。
			因为like '%%' 表示的是不为空,而如果`commission_pct`或者`last_name`有一个为空,结果就不一样了。

5.3 排序查询

-- 进阶3:排序查询
/*
1.语法: [ ]里面的内容表示可以省略的
			select 查询列表
			from 表名
			[where  筛选条件]
			order by 排序列表 [asc | desc];
2.特点:
			1、asc代表的是升序,desc代表的是降序(如果不写,默认就是降序)
			2、order by子句中可以支持单个字段、多个字段、表达式、函数、别名
			3、order by子句一般是放在查询语句的最后面的,limit子句除外
*/
-- 案例1:查询员工信息,要求工资从高到低排序
SELECT
	* 
FROM
	employees 
ORDER BY
	salary DESC;

-- 案例2:查询员工信息,要求工资从低到高排序
SELECT
	* 
FROM
	employees 
ORDER BY
	salary;
	
-- 案例3:查询部门编号>=90的员工信息,按入职时间先后进行排序(升序)[添加筛选条件]
SELECT
	* 
FROM
	employees 
WHERE
	department_id >= 90 
ORDER BY
	hiredate ASC;
	
-- 案例4:按年薪的高低显示员工的信息和年薪[按表达式排序]	
SELECT
	*,
	salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) 年薪 
FROM
	employees 
ORDER BY
	salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) DESC;

-- 案例5:按年薪的高低显示员工的信息和年薪[按别名排序]	
SELECT
	*,
	salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) 年薪 
FROM
	employees 
ORDER BY
	年薪 DESC;
	
-- 案例6:按姓名的长度显示员工的姓名和工资[按函数排序]
SELECT
	LENGTH( last_name ) 字节长度,
	last_name,
	salary 
FROM
	employees 
ORDER BY
	LENGTH( last_name ) DESC;
	
-- 案例7:查询员工信息,要求先按工资升序排序,再按员工编号降序排序[按多个字段排序]
SELECT
	* 
FROM
	employees 
ORDER BY
	salary ASC,
	employee_id DESC;

5.3.1 排序查询练习

-- 1. 查询员工的姓名和部门号和年薪,按年薪降序 按姓名升序
SELECT
	last_name,
	department_id,
	salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) 年薪 
FROM
	employees 
ORDER BY
	年薪 DESC,
	last_name ASC;

-- 2. 选择工资不在 8000 到 17000 的员工的姓名和工资,按工资降序
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	salary NOT BETWEEN 8000 
	AND 17000 
ORDER BY
	salary DESC;

-- 3. 查询邮箱中包含 e 的员工信息,并先按邮箱的字节数降序,再按部门号升序
SELECT
	*,
	LENGTH( email ) 邮箱字节数 
FROM
	employees 
WHERE
	email LIKE '%e%' 
ORDER BY
	邮箱字节数 DESC,
	department_id ASC;

5.4 常见函数

常见函数:
			字符函数:
			length 获取字节个数
			concat 拼接
			substr 截取子串
			instr 返回子串第一次出现的索引
			trim 去前后指定的空格和字符
			upper 转换成大写
			lower 转换成小写
			lpad 左填充
			rpad 右填充
			replace 替换
			
			数学函数:
			round 四舍五入
			ceil 向上取整
			floor 向下取整
			truncate 截断
			mod 取余
			rand 获取随机数,返回0-1之间的小数 [0,1)
			
			日期函数:
			now 当前日期+时间
			curdate 返回当前日期
			curtime 返回当前时间
			yearmonth 月
			monthname 以英文形式返回月
			dayhour 小时
			minute 分钟
			second 秒
      datediff 返回两个日期相差的天数
			str_to_date 将字符转换成日期
			date_format 将日期转换成字符     
			
			其他函数:
			version 当前数据库服务器的版本号
			database 当前打开的数据库
			user 当前用户
      password('字符') 返回该字符的密码形式(自动加密) 注意:8版本不支持此种加密方式
			md5('字符') 使用md5加密形式对该字符进行加密
                             
			流程控制函数:
			if(条件表达式,表达式1,表达式2) 如果条件表达式成立,返回表达式1,否则返回表达式2
			case(两种情况)
            case情况一:
                      case 变量或表达式或字段
                      when 常量1 then1
                      when 常量2 then2 
                        ...
                      else 值n
                      end
             case情况二:    
                      case 
                      when 条件1 then1
                      when 条件2 then2 
                        ...
                      else 值n
                      end
                             
        分组函数:
        max 最大值
        min 最小值
        sum 总和
        avg 平均值
        count 计算个数                                          
-- 进阶4:常见函数
/*
概念:类似于Java中的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:1、隐藏了实现细节  2、提高代码的重用性
调用:select 函数名(实参列表) [from 表名]
特点:
		①叫什么(函数名)
		②干什么(函数的功能)
分类:
		1、单行函数
		如:concat、length、ifnull等
		2、分组函数
		功能:做统计使用的,又称为统计函数、聚合函数、组函数
*/

-- 1.字符函数
-- 1.1 length 获取参数值的字节个数
SELECT
	LENGTH( 'john' );
	
SELECT
	LENGTH( '张三丰haha' );

-- 获取当前mysql的字符集
SHOW VARIABLES LIKE '%char%';

-- 1.2 concat 拼接字符串
SELECT
	CONCAT( last_name, '_', first_name ) 姓名 
FROM
	employees;

-- 1.3 upper:将指定字符变成大写的,lower:将指定字符变成小写的
SELECT
	UPPER( 'john' );

SELECT
	LOWER( 'joHn' );
	
-- 案例:将姓变大写,名变小写,然后拼接
SELECT
	CONCAT( UPPER( last_name ), LOWER( first_name ) ) 姓名 
FROM
	employees;
	
-- 1.4 substr、substring  注意:索引都是从1开始的

-- 方法一:截取从指定索引处后面的所有字符
SELECT
	SUBSTR( '李莫愁爱上了陆展元', 7 ) out_put; # 陆展元
	
-- 方法二:截取从指定索引处指定字符长度的字符
SELECT
	SUBSTR( '李莫愁爱上了陆展元', 1, 3 ) out_put; # 李莫愁

-- 案例:姓名中首字符大写,其他字符小写然后用_拼接,显示出来
SELECT
	CONCAT(
		UPPER( SUBSTR( last_name, 1, 1 ) ),
		'_',
		LOWER( SUBSTR( last_name, 2 ) ) 
	) 姓名 
FROM
	employees;

-- 1.5 instr 返回指定字符在另一个指定字符中第一次出现的索引,如果找不到返回0
SELECT
	INSTR( '杨不殷六侠悔爱上了殷六侠', '殷八侠' ) AS out_put; # 0
	
SELECT
	INSTR( '杨不殷六侠悔爱上了殷六侠', '殷六侠' ) AS out_put; # 3
	
-- 1.6 trim 

-- 方法一:去掉前后的空格
SELECT
	LENGTH( TRIM( '    张翠山    ' ) ) AS out_put; # TRIM( '    张翠山    ' )返回'张翠山'
	
-- 方法二:过滤掉前后指定的字符
SELECT
	TRIM( 'aa' FROM 'aaaaaaaaa张aaaaaaaaaaaa翠山aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ) AS out_put;
# a张aaaaaaaaaaaa翠山a
	
-- 1.7 lpad 用指定的字符实现左填充指定长度
SELECT
	LPAD( '殷素素', 10, 'A' ) AS out_put; # AAAAAAA殷素素

SELECT
	LPAD( '殷素素', 2, 'A' ) AS out_put; # 殷素

-- 1.8 rpad 用指定的字符实现右填充指定长度
SELECT
	RPAD( '殷素素', 12, 'ab' ) AS out_put; # 殷素素ababababa
	
-- 1.9 replace 替换
SELECT REPLACE
	( '周芷若周芷若周芷若周芷若张无忌爱上了周芷若', '周芷若', '赵敏' ) AS out_put;
# 赵敏赵敏赵敏赵敏张无忌爱上了赵敏
-- 2.数学函数

-- 2.1 round 

-- 方法一:四舍五入
SELECT
	ROUND( - 1.55 );# -2

-- 方法二:小数点后保留几位小数
SELECT
	ROUND( 1.567, 2 );# 1.57

-- 2.2 ceil 向上取整,返回>=该参数的最小整数
SELECT CEIL(1.002); # 2
SELECT CEIL(-1.02); # -1

-- 2.3 floor 向下取整,返回<=该参数的最大整数
SELECT FLOOR(9.8); # 9
SELECT FLOOR(-9.99); # -10

-- 2.4 truncate 截断,小数点后保留几位小数
SELECT TRUNCATE(1.69999,1); # 1.6

-- 2.5 mod 取余,左边的数是正数,结果就是正的,反之则为负数
/*
mod(a,b) 相当于 a - a/b * b
mod(-10,-3) : -10 - (-10)/(-3) * (-3) = -1
mod(10,-3) : 10 - 10/(-3) * (-3) = 1
*/
SELECT MOD(10,3); # 1
SELECT MOD(10,-3); # 1
SELECT MOD(-10,3)# -1

-- 3.日期函数

-- 3.1 now 返回当前系统日期+时间
SELECT NOW(); # 2020-10-04 18:12:56

-- 3.2 curdate 返回当前系统日期,不包含时间
SELECT CURDATE(); # 2020-10-04

-- 3.3 curtime 返回当前时间,不包含日期
SELECT CURTIME(); # 18:16:18

-- 3.4 可以获取指定的部分,年、月、日、小时、分钟、秒
SELECT YEAR(NOW()); # 2020
SELECT YEAR('1999-04-28'); # 1999

SELECT YEAR(hiredate)FROM employees;

SELECT MONTH(NOW()); # 10
SELECT MONTHNAME(NOW()); # October

-- 3.5 str_to_date 将字符通过指定的格式转换成日期
SELECT STR_TO_DATE('1999-4-28','%Y-%c-%d') 日期; # 1999-04-28

-- 案例:查询入职日期为1992-4-3的员工信息
SELECT * FROM employees WHERE hiredate = '1992-4-3';
-- 在开发中有可能从前端返回的日期字符串是没有顺序的,这个时候就要用到我们的格式转换,才能查询出数据
SELECT * FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y');

-- 3.6 date_format 将日期转换成字符
SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS 日期; # 20年10月04日

-- 案例:查询有奖金的员工名和入职日期,要求入职日期的格式是:(xx月/xx日 xx年)
SELECT
	last_name,
	DATE_FORMAT( hiredate, '%m月/%d日 %y年' ) 入职日期 
FROM
	employees 
WHERE
	salary IS NOT NULL;

-- 4.其他函数

-- 4.1 version 查看当前系统的mysql版本号
SELECT VERSION(); # 8.0.19

-- 4.2 database 查看当前所在数据库
SELECT DATABASE(); # myemployees

-- 4.3 user 查看当前用户
SELECT USER(); # [email protected]

-- 5.流程控制函数

-- 5.1 if函数 实现if-else的效果
SELECT IF(10>5,'大','小'); # 大

SELECT
	last_name,
	commission_pct,
IF
	( commission_pct IS NULL, '没奖金,呵呵', '有奖金,嘻嘻' ) 备注 
FROM
	employees;

-- 5.2 case函数

-- 5.2.1 case函数的使用一:实现switch-case的效果
/*
Java中
switch(表达式){
case 常量1:
			执行语句1;
			break;
case 常量2:
			执行语句2;
			break;
...
defaule:
			执行语句n;
			break;
			
mysql中
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1
when 常量2 then 要显示的值2或语句2
...
else 要显示的值n或语句n
end
*/

/*案例:查询员工的工资,要求

部门号=30,显示的工资为1.1倍
部门号=40,显示的工资为1.2倍
部门号=50,显示的工资为1.3倍
其他部门,显示的工资为原工资
*/
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;

-- 5.2.2 case函数的使用二:类似于 多重if的效果
/*
java中:
if(条件1){
	语句1;
}else if(条件2){
	语句2;
}
...
else{
	语句n;
}

mysql中:
case
when 条件1 then 要显示的值1或语句1
when 条件2 then 要显示的值2或语句2
...
else 要显示的值n或语句n
end
*/

/*
案例:查询员工的工资的情况
如果工资>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;

5.4.1 常见函数练习

-- 1. 显示系统时间(注:日期+时间)
SELECT NOW();

-- 2. 查询员工号,姓名,工资,以及工资提高百分之 20%后的结果(new salary)
SELECT
	employee_id,
	last_name,
	salary,
	salary * ( 1+0.2 ) AS "new salary" 
FROM
	employees;

-- 3. 将员工的姓名按首字母排序,并写出姓名的长度(length)
SELECT
	last_name,
	LENGTH( last_name ) 姓名长度,
	SUBSTR( last_name, 1, 1 ) 首字母 
FROM
	employees 
ORDER BY
	首字母 ASC;

-- 4. 做一个查询,产生下面的结果
/*
<last_name> earns <salary> monthly but wants <salary*3>
									Dream Salary
			King earns 24000 monthly but wants 72000
*/
SELECT
	CONCAT(
		last_name,
		' earns ',
		salary,
		' monthly but wants ',
		salary * 3 
	) AS "Dream Salary" 
FROM
	employees 
WHERE
	salary = 24000;
	
-- 5. 使用 case-when,按照下面的条件: 
/*
										job 						grade 
									AD_PRES             A 
									ST_MAN              B
									IT_PROG             C
									SA_REP              D
									ST_CLERK            E
									
									产生下面的结果
last_name					job_id					Grade
  K_ing						AD_PRES	          A
	 
*/
SELECT last_name,job_id,
CASE job_id
	WHEN 'AD_PRES' THEN 'A'
	WHEN 'ST_MAN' THEN 'B'
	WHEN 'IT_PROG' THEN 'C'
	WHEN 'SA_REP' THEN 'D'
	WHEN 'ST_CLERK' THEN 'E'
END AS 'Grade' FROM employees WHERE job_id = 'AD_PRES';

5.5 分组函数

-- 进阶4:常见函数2

-- 分组函数
/*
功能:用作统计使用,又称为聚合函数或统计函数或组函数

分类:
sum 求和 、 avg 平均值 、 max 最大值 、 min 最小值 、 count 计算个数

特点:
1、sum、avg一般用于处理数值型
   max、min、count可以处理任何类型
2、以上分组函数都忽略null值

3、可以和distinct搭配实现去重的运算

4、count函数的单独介绍
count(字段):统计该字段非空值的个数
一般使用count(*)用作统计行数
另外 count(1)也是用来统计行数

5、和分组函数一同查询的字段要求是group by后的字段
*/

-- 1.简单的使用
SELECT SUM(salary) 工资总和 FROM employees;
SELECT AVG(salary) 工资平均值 FROM employees;
SELECT MIN(salary) 最小工资 FROM employees;
SELECT MAX(salary) 最大工资 FROM employees;
SELECT COUNT(salary) 总共多少份工资 FROM employees;

SELECT
	SUM( salary ) 工资总和,
	AVG( salary ) 工资平均值,
	MIN( salary ) 最小工资,
	MAX( salary ) 最大工资,
	COUNT( salary ) 总共多少份工资 
FROM
	employees;
	
SELECT
	SUM( salary ) 工资总和,
	ROUND( AVG( salary ), 2 ) "工资平均值(保留2位小数)",
	MIN( salary ) 最小工资,
	MAX( 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; 
SELECT COUNT(last_name) FROM employees;

-- 3.是否忽略null:都忽略null值
SELECT
	SUM( commission_pct ),
	AVG( commission_pct ),
	SUM( commission_pct ) / 35,
	SUM( commission_pct ) / 107 
FROM
	employees; 
	
SELECT MAX(commission_pct) ,MIN(commission_pct) FROM employees;
SELECT COUNT(commission_pct) FROM employees;
SELECT commission_pct FROM employees;

-- 4.和distinct搭配
SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;

SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;


-- 5.count函数的详细介绍
/*
效率:
MYISAM存储引擎下  ,COUNT(*)的效率高
INNODB存储引擎下,COUNT(*)和COUNT(1)的效率差不多,比COUNT(字段)要高一些
*/
SELECT COUNT(salary) FROM employees;

SELECT COUNT(*) FROM employees; # 经常用来统计行数 107

SELECT COUNT(1) FROM employees; # 107

-- 6.和分组函数一同查询的字段有限制
SELECT AVG(salary),employee_id FROM employees; #报错

5.5.1 分组函数练习

-- 1. 查询公司员工工资的最大值,最小值,平均值(保留两位小数),总和,并按 job_id 升序
SELECT
	MAX( salary ) 最大值,
	MIN( salary ) 最小值,
	ROUND( AVG( salary ), 2 ) 平均值,
	SUM( salary ) 总和 
FROM
	employees 
ORDER BY
	job_id ASC;

-- 2. 查询员工最高工资和最低工资的差距(DIFFERENCE)
SELECT
	( MAX( salary ) - MIN( salary ) ) DIFFERENCE 
FROM
	employees;

-- 3. 查询各个管理者手下员工的最低工资,其中最低工资不能低于 6000,没有管理者的员工不计算在内
SELECT

-- 4. 查询所有部门的编号,员工数量和工资平均值,并按平均工资降序

-- 5. 选择具有各个 job_id 的员工人数

-- 6. 查询员工表中的最大入职时间和最小入职时间的相差天数(DIFFERENCE)
SELECT DATEDIFF(MAX(hiredate),MIN(hiredate)) DIFFERENCE FROM employees;

-- 7. 查询某人从出生到现在的总天数
SELECT DATEDIFF(NOW(),'1999-04-28') 总天数;

-- 8.查询部门编号为90的员工个数
SELECT
	COUNT( * ) 
FROM
	employees 个数
WHERE
	department_id = 90;

5.6 分组查询

-- 进阶5:分组查询
/*
		语法:  [ ]里面的内容表示可以省略的
		select 查询列表         		①
		from 表           					②
		[where 筛选条件]   					③
		group by 分组的字段 				  ④
		[having 分组后的筛选]        ⑤
		[order by 排序的字段];				⑥
		
		执行顺序:② -> ③ -> ④ - > ⑤ -> ① -> ⑤
注意:
		和分组函数一同查询的字段必须是group by后出现的字段
		
特点:
		1.分组查询中的筛选条件分为两类
										数据源 											位置									关键字
		分组前筛选		原始表(真实存在的表)					group by子句的前面					where
		分组后筛选     分组后的结果集							group by子句的后面					having
		
		① 分组函数做筛选条件,肯定是放在having子句中
		② 能用分组前筛选的,就优先考虑使用分组前筛选(性能问题)
		2.group by子句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开并且没有顺序要求),
				表达式或函数(用得较少)
		3.也可以添加排序(排序放在整个分组查询的最后)
*/
-- 1.简单的分组查询

-- 案例1:查询每个工种的最高工资
SELECT
	MAX( salary ),
	job_id 
FROM
	employees 
GROUP BY
	job_id;

-- 案例2:查询每个位置上的部门个数
SELECT
	COUNT( * ),
	location_id 
FROM
	departments 
GROUP BY
	location_id;

-- 2.添加分组前的筛选条件

-- 案例1:查询邮箱中包含a字符的,每个部门的平均工资
SELECT
	AVG( salary ),
	department_id 
FROM
	employees 
WHERE
	email LIKE '%a%' 
GROUP BY
	department_id;

-- 案例2:查询有奖金的每个领导手下员工的最高工资
SELECT
	MAX( salary ),
	manager_id 
FROM
	employees 
WHERE
	commission_pct IS NOT NULL 
GROUP BY
	manager_id;

-- 3.添加分组后的筛选条件

-- 案例1:查询哪个部门的员工个数>2

-- ① 查询每个部门的员工个数
SELECT
	COUNT( * ),
	department_id 
FROM
	employees 
GROUP BY
	department_id;
	
-- ② 根据①的结果进行筛选,查询哪个部门的员工个数>2
SELECT
	COUNT( * ),
	department_id 
FROM
	employees 
GROUP BY
	department_id 
HAVING
	COUNT( * ) > 2;

-- 案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资

-- ① 查询每个工种有奖金的员工的最高工资
SELECT
	job_id,
	MAX( salary ) 
FROM
	employees 
WHERE
	commission_pct IS NOT NULL 
GROUP BY
	job_id;
	
-- ② 根据①的结果继续筛选,最高工资>12000
SELECT
	job_id,
	MAX( salary ) 
FROM
	employees 
WHERE
	commission_pct IS NOT NULL 
GROUP BY
	job_id 
HAVING
	MAX( salary ) > 12000;

-- 案例3:查询领导编号>102的每个领导手下的最低工资>5000的领导编号和最低工资
SELECT
	manager_id,
	MIN( salary ) 
FROM
	employees 
WHERE
	manager_id > 102 
GROUP BY
	manager_id 
HAVING
	MIN( salary ) > 5000;
	
-- 4.按表达式或函数分组

-- 案例1:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些

-- ① 查询每个长度的员工个数
SELECT
	COUNT( * ),
	LENGTH( last_name ) 姓名长度 
FROM
	employees 
GROUP BY
	LENGTH( last_name );

-- ② 添加筛选条件
SELECT
	COUNT( * ) c,
	LENGTH( last_name ) 姓名长度 
FROM
	employees 
GROUP BY
	姓名长度 
HAVING
	c > 5;

-- 5.按多个字段进行分组

-- 案例1:查询每个部门每个工种的员工的平均工资
SELECT
	AVG( salary ),
	department_id,
	job_id 
FROM
	employees 
GROUP BY
	department_id,
	job_id;

-- 6.添加排序

-- 案例1:查询每个部门每个工种的员工的平均工资,并且按平均工资的高低显示,要求部门id不能为null,平均工资要大于10000
SELECT
	AVG( salary ),
	department_id,
	job_id 
FROM
	employees 
WHERE
	department_id IS NOT NULL 
GROUP BY
	department_id,
	job_id 
HAVING
	AVG( salary ) > 10000 
ORDER BY
	AVG( salary ) DESC;

5.6.1 分组查询练习

-- 1. 查询各 job_id 的员工工资的最大值,最小值,平均值,总和,并按 job_id 升序
SELECT
	job_id,
	MAX( salary ) 最大值,
	MIN( salary ) 最小值,
	ROUND( AVG( salary ), 2 ) 平均值,
	SUM( salary ) 总和 
FROM
	employees 
GROUP BY
	job_id 
ORDER BY
	job_id ASC;

-- 2. 查询员工最高工资和最低工资的差距(DIFFERENCE)
SELECT
	( MAX( salary ) - MIN( salary ) ) DIFFERENCE 
FROM
	employees;
	
-- 3. 查询各个管理者手下员工的最低工资,其中最低工资不能低于 6000,没有管理者的员工不计算在内
SELECT
	manager_id,
	MIN( salary ) 最低工资 
FROM
	employees 
WHERE
	manager_id IS NOT NULL 
GROUP BY
	manager_id 
HAVING
	MIN( salary ) > 6000;

-- 4. 查询所有部门的编号,员工数量和工资平均值,并按平均工资降序
SELECT
	department_id,
	COUNT( * ) 员工数量,
	AVG( salary ) 平均工资 
FROM
	employees 
GROUP BY
	department_id 
ORDER BY
	AVG( salary ) DESC;

-- 5. 查询各个 job_id 的员工人数
SELECT
	job_id,
	COUNT( * ) 员工人数 
FROM
	employees 
GROUP BY
	job_id;