2.选择工资不在8000到12000的员工的姓名和工资,按工资降序 mysql > select concat(first_name,last_name) 姓名,salary 工资 from employees where salary between 8000 and 12000 order by salary desc; 3.查询邮箱中包含e的员工信息,并选择邮箱的字节降序,再按部门编号升序 mysql > select * from employees where email like '%e%' order by length(email) desc,department_id asc; 进阶4:常函数----类似于Java中的方法,将一组逻辑语句封装到方法体中,对外暴露方法名 1.好处:隐藏实现细节 ,提高代码的重用性 2.语法:select 函数(参数列表) [from 表名] 3.分类: 1.单行字符: 1.字符函数 1.length----计算字符的字节长度 案例:员工表中员工姓名的长度 msql > select concat(first_name,last_name) as 姓名, length(concat(first_name,last_name)) 名字的长度 from employees; ----一个字符占一个长度 案例: mysql > select length("张三丰hahahhaha"); ----一个汉字占三个字节 2.concat---拼接,上面案例 3.upper,lower----字符全转大写,全转小写 案例:将员工表中的姓名全传大写,全转小写 mysql > select upper(concat(first_name,last_name)) 姓名 from employees; mysql > select lower(concat(first_name,last_name)) 姓名 from employees; 4.substr,substring----截取,mysql中索引都是从1开始 案例: mysql > select substr("李莫愁爱上了陆展元",7); mysql > select substr("李莫愁爱上了陆展元",1,3); -----包含1,3指的是长度 mysql > select substring("李莫愁爱上了陆展元",7); mysql > select substring("李莫愁爱上了陆展元",1,3); 5.instr---返回子字符串第一次出现索引,如果没有则返回0 案例: mysql > select instr("杨不悔爱上了殷六侠","殷六侠"); 6.trim--去掉首尾的空格或者指定字符 案例: msyql > select trim(" 赵翠三 adjfkfjk "); 案例: msyql > select trim('a' from "aaaaaaaaaaaaaaaa张aaaaaaaaaaaaaaaa翠aaaaaaaaa山aaaaaaaaaaa") as output ; 7.lpad---使用指定的字符左填充指定长度 案例: mysql > select lpad("殷素素“,10,"*");----字符串小于10个字符时,左边使用“*"来填充 mysql > select lpad('殷素素',2,'*');-------当指定长度小于原有的字符串长度时,截取原有的字符串长度 8.rpad-----用指定的字符右填充指定长度 案例: msyql > SELECT RPAD('殷素素',10,'你是一个笨蛋淡淡的'); 9.replace----使用指定字符来替代字符串中的字符串或者字符串本身 案例: mysql > select replace('张无忌爱上了周芷若','周芷若','赵敏'); -----使用赵敏来替代周芷若 2.数学函数 1.round---四舍五入 案例: mysql > select round(1.65); mysql > select round(-1.65); mysql > select round(1.45678,3);-----3表示保留几位小数 2.ceil----向上取整(返回>=该参数的最小整数) 案例: mysql > select ceil(1.002); mysql > select ceil(-1.02); 3.floor---向下取整(返回<=该数的最大整数) 案例: mysql > select floor(-9.99); 4.truncate---截取----不四舍五入 案例: mysql > select truncate(1.68888,3);----3表示小数点保留3位,不四舍五入 mysql > select truncate(666666666,3); ---对整数不起作用 5.mod(a,b)---取余----(a-a/b*b)---a为负数,则结果为负数,a为正数,则结果为正数 案例: mysql > select mod(-10,-3);------(-10-(-10/-3)*(-3)) = -10 - 3*(-3) = -1 3.日期函数 1.now()---表示返回当前日期,时间 案例: mysql > select now(); 2.curdate----显示当前的日期,不包括时间 案例: mysql > select curdate(); 3.curtime---显示时间,不包括日期 案例: mysql > select curtime(); 4.获得指定部分---year(),month(),monthname(),day(),hour(),minute(),second() 案例: mysql > select year(hiredate) 入职年份 from employees; 案例: mysql > select month(now()); mysql > select day("2020-9-24"); 5.str_to_date----将字符通过指定的格式转换成日期 案例:查询入职日期为1992-4-2的员工的姓名,月薪 mysql > select concat(first_name,last_name) 姓名,salary 月薪 from employees where hiredate = str_to_date('4-3-1992','%c-%d-%Y'); 6.date_formate----将日期转换为字符串 案例:查询有奖金的员工的姓名和入职日期(xx月/xx日/xx年 mysql > select concat(first_name,last_name) 姓名,date_format(hiredate,"%m/%d/%y") as 入职日期 from employees where commission_pct is not null; 注意: %Y---四位数的年份 %y---2位数的年份 %m--月份(01,02,....12) %c---月份(1,2,3,4....12) %d---日 %H---小时(24小时制) %h---小时(12小时制) %i----分钟 %s----秒 7.日期函数-----datediff(表达式1,表达式2)----返回表达式1-表达式2的值 案例:查询员工表中最大的入职时间和最小的入职时间的相差天数 mysql > select max(hiredate) 最晚的入职时间, min(hiredate) 最早的入职时间,datediff(max(hiredate),min(hiredate)) 相差天数 from employees; 4.其他函数 version(),database()---查看当前的库,user()------查看当前的用户 5.流程控制函数 1.if(表达式1,表达式2,表达式3)函数-------相当于Java中的三元运算符,表达式1为真,则返回表达式2,否则返回表达式3 案例: mysql > select concat(first_name,last_name) 姓名,commission_pct 奖金, if(commission_pct,"有奖金","没奖金") 奖金情况 from employees; ----commission_pct为null时,表示为假,返回表达式3 2.case函数 1.语法:-----相当于Java中的switch case的效果 case 要判断的字段或表达式 when 常量1 then 要显示的值1或语句1; when 常量2 then 要显示的值2或语句2; ....... else 要显示的值n或语句n; end 注意: 1.上面黄色的部分: 1.如果case放置在select的后面使用,相当于一个表达式,那么黄色的部分就不能是一个表达式了, 只能是一个值,并且没有分号";" 2.如果case放置在存储过程就可以将其当做语句使用,可以不搭配select使用,这是黄色部分放的是语句,需要加上分号";" 案例: 部门号 = 30,显示工资为1.1倍 部门号 = 40,显示工资为1.2倍 部门号 = 50,显示工资为1.3倍 其他 原工资 显示这些员工的姓名,原工资,上涨的工资 mysql > select concat(first_name,last_name) 姓名,department_id 部门号,salary 原工资, 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; 2. 语法:-----类似于Java中的多重if case when 条件1 then 要显示的值1或语句1; when 条件2 then 要显示的值2或语句2; ......... else 要显示的值n或语句n; end 案例: 部门员工的工作情况: 如果工资 > 20000,显示A 如果工资 > 15000显示B 如果工资 > 10000显示C 其他 显示D mysql > select concat(first_name,last_name) 姓名,salary 工资, case when salary > 20000 then 'A' when salary between 15000 and 20000 then 'B' when salary between 10000 and 15000 then 'C' else 'D' end as 工资级别 from employees; 2.分组函数 1.功能:用作统计使用,又称为聚合函数或统计函数或组函数 2.分类: sum--求和,avg---平均,max---最大值,min---最小值,count---计算个数 3.简单使用: mysql > select sum(salary) 总工资,avg(salary) 平均工资,max(salary) 最大的工资,min(salary) 最小的工资,count(salary) 员工个数 from employees; 4.参数类型支持哪些类型 1.sum,avg只支持数值类型 2.max,min,count支持任意类型 5.是否忽略null sum,avg,max,min,count都忽略null,count计算的是非空个数 6.可以和distinct搭配使用起到去重计算的效果 mysql > select sum(distinct salary) from employees; ----与上面的总工资相比,达到了去重的效果 7.count函数的详细介绍 1. mysql > select count(commisssion_pct) from employees; 2.mysql > select count(*) from employees; 3.mysql > select count(1) from employees; 总结: 1).1中的结果与2,3的结果不一样,因为1中会忽略null 2).count(*)中的“*”表示任意字段,在每一行中,如果有一个字段不为Null,那就代表这一行不为null,要计1行 3).count(1)这相当于在表中增加了一个虚拟字段,其值都为1,所以其结果与count(salary)一样(这是因为salary中没有null) 4)效率:在mysam存储引擎中,count(*)效率最高,在innodb存储引擎中,count(*)和count(10的效率差不多,比count(字段)要高一些 8.和分组函数一同查询的字段有限制-----要求是group by后的字段 mysql > select avg(salary),employee_id from employees;-------avg(salary)一行,employee_id为107行 进阶5:分组 1.group by---将表中的所有数据按照要求分成若干个组 2.语法: select 查询列表------【分组函数,列(出现在grop by的后面)】 from 表名 [where 筛选条件] group by 分组的列名 [order by 子句] 注意:查询列表特殊,要求是分组函数和group by后出现的字段 案例: 1.查询每个工种的最高工资 mysql > select max(salary) 最高工资,job_id as 工种编号 from employees group by job_id; 2.查询每个位置上的部门个数 mysql > select count(*) 部门个数,loacation_id as 位置号 from departments group by location_id; 3.添加筛选条件----分组前,使用where 案例:查询邮箱中包含a字符的每个部门的平均工资 msyql > select avg(salary) 平均工资,department_id 部门编号 from employees where email like '%a%' group by department_id; 查询有奖金的每个领导手下员工的最高工资 mysql > select max(salary) 最高工资,manager_id 领导编号 from employees where commission_pct is not null group by manager_id; 4.添加复杂的筛选条件---分组后,使用having 案例:查询那个部门的员工个数>2 mysql > select department_id 部门编号,count(*) 员工个数 from employees group by department_id having count(*) > 2; 查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资 mysql > select job_id 工种编号,max(salary) 最高工资 from employees where commission_pct is not null group by job_id having max(salary) > 12000; 查询领导编号>102的每个领导手下的最低工资>5000的领导编号以及最低工资 mysql > select manager_id 领导编号,min(salary) 最低工资 from employees where manager_id > 102 group by manager_id having min(salary) > 5000; 比较: 分组查询中的筛选条件分为两种情况: 数据源 位置 关键字 分组前筛选 原始表 group by 字句之前 where 分组后筛选 分组后的结果集 group by 字句之后 having 1.分组函数做条件肯定是放在having子句中 2.分组前筛选的,就优先考虑使用分组前筛选 3.where子句作用于表和视图,having子句作用于组 4.where在分组和聚集计算之前选取输入行(因此,它控制哪些行进入聚集计算),而having在分组和聚集之后选取分组的行。因此,where子句不能包含聚集函数;因为试图用聚集函数判断那些行输入给聚集运算时没有意义的。想反,having子句总是包含聚集函数(严格来说,可以不使用聚集的having子句,但这样做是没有意义的,同样的条件可以更有效的用于where阶段) 5.having一般跟在group by之后,执行记录组选择的一部分来工作的,where则是执行所有数据来工作的,再者having可以用来聚合函数 5.按表达式或函数分组 案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些 mysql > select count(*) 员工个数,length(concat(first_name,last_name)) 姓名长度 from employees group by length(concat(first_name,last_name)) having count(*) > 5; 6.按多个字段分组----逗号隔开 案例:查询每个部门每个工种的员工的平均工资 mysql > select avg(salary) 平均工资,department_id 部门编号,job_id 工种编号 from employees group by department_id,job_id ; 7.添加排序 案例:查询每个部门每个工种的员工的平均工资,并且按平均工资的高低显示 msyql > select avg(salary) 平均工资,department_id 部门编号,job_id 工种编号 from employees group by department_id,job_id order by 平均工资 desc; 总结: 1.group by子句支持单个字段分组,多个字段分组(多个字段之间使用逗号隔开,没有顺序要求),表达式或函数 2.也可以添加排序(排序放在整个分组查询的最后) 案例:查询各job_id的员工工资的最大值,最小值,平均值,总和,并按Job_id升序 mysql > select job_id 工种编号 max(salary) 最高工资,min(salary) 最小工资,avg(salary) as 平均工资,sum(salary) 总和 from employees group by job_id order by job_id asc; 案例:查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内 mysql > select min(salary) 最低工资,manager_id 领导编号 from employees where manager_id is not null group by manager_id having 最低工资 > 6000; 案例:查询所有部门的编号,员工数量,工资平均值,并按平均工资降序 mysql > select count(*) 员工个数,avg(salary) 平均工资,department_id 部门编号 from employees group by department_id order by 平均工资 desc; 进阶6:连接查询 1.含义:又称为多表查询,当查询的字段不在同一个表时,就会用到连接查询 2.笛卡尔积现象:表1有m行,表2有n行,结果为m*n行 3.发生原因:没有有效的连接条件 4.如何避免:添加有效的连接条件 5.分类: 1.sql92标准----只支持内连接 2.sql99标准----支持内连接,外连接,交互连接 6.按功能分为: 内连接:等值连接,非等值连接,自连接 外连接:左外连接,右外连接,全外连接(mysql不支持) 交互连接 sql92标准 1.等值连接 案例:查询女神和对应的男神名 mysql > use girls; mysql > SELECT beauty.name 女神名,boyName 男神名 FROM beauty ,boys WHERE beauty.`boyfriend_id` = boys.id; -----使用的是表名.字段 2.为表起别名----与字段起别名一样,两种方法,好处为:提高语句的简洁度,区分重名字段 案例:查询员工名,工种名,工种号 mysql > use myemployees; mysql > SELECT CONCAT(first_name,last_name) 员工姓名,e.job_id 工种号,job_title 工种名 FROM employees e,jobs j WHERE e.`job_id` = j.`job_id`; ---两个好处都体现了,在该案例中 注意: 1.字段e.job_id这里如果表已经起了别名,就不能再使用beauty.boy_id,因为在执行一条sql语句时,总是从from表名开始的 2.在where中不能使用别名,在group by ,order by中可以使用别名 3.两个表之间的顺序是任意的 4.可以筛选 案例:查询有奖金的员工名,部门名 mysql > select concat(first_name,last_name) 员工名,department_name 部门名 from employees as e,departments as d where e.department_id = d.department_id and commission_pct is not null; 案例:查询城市名中第二个字符为o的部门名和城市名 msyql > select department_name 部门名,city 城市名 from departments d,locations l where d.location_id = l.location_id and city like '_o%'; 5.可以加分组 案例:查询每个城市的部门个数 mysql > select count(d.department_id) 部门个数,city 城市名 from locations l,departments d where d.location_id = l.location_id group by city; ---count(department_id)可以使用count(*)来代替 案例:查询有奖金的某个部门的部门名和部门的领导编号和该部门的最低工资 mysql > select min(salary) 最低工资,department_name 部门名,manager_id 领导编号 from employees e,departments d where d.department_id = e.department_id and commission_pct is not null group d.department_id; 6.可以加排序 案例: 查询每个工种的工种名和员工个数,并且按员工个数降序 mysql > select j.job_title as 工种名, count(*) 员工个数 from employees as e,jobs j where e.job_id = j.job_id group by j.job_id order by count(*) desc; 7.多表链接 案例:查询员工名,部门名,所在的城市 mysql > select concat(first_name,last_name) as 员工名,department_name 部门名,city 城市名 from employees e, departments d,locations l where e.department_id = d.department_id and d.location_id = l.location_id; 等值连接总结: 1.多表等值连接的结果为多表的交集部分 2.n表连接,需要n-1个连接条件 3.多表没有顺序要求 4.一般需要为各个表起别名 5.可以搭配前面介绍的所有子句使用,比如排序,分组,筛选 2.非等值连接-----除了不为“=”,都为非等值 案例:查询员工的工资和工资级别 mysql > select salary 工资,grade_level 工资级别 from employees,job_grades where salary between lowest_sal and highest_sal; 3.自连接 案例:查询员工名和上级名称 mysql > select concat(e1.first_name,e1.last_name) 员工名,concat(e2.first_name,e2.last_name) 上级名 from employees e1,employees e2 where e1.manager_id = e2.employee_id; sql 99: 1. 内连接:等值,非等值,自连接 2.外连接:左外连接,右外连接,完全连接(mysql不支持) 3.交互连接 1.等值连接-----与sql 92标准一样 语法:select 查询列表 from 表1 [as] 别名, 表2 [as] 别名 where 表1的别名.key = 表2的别名.key [and 筛选条件] [group by 分组条件] [ having 分组后的筛选条件] [ order by 排序实现] 特点: 1.一般为表起别名 2.多表的顺序可以调换 3.n个表连接需要n-1个条件 4.等值连接为多表的交集部分 2.非等值连接----上面的where中的“=”换成“非=” 3.自连接 案例: 1.显示所有员工的姓名,部门名和部门号 mysql > select concat(first_name,last_name) 员工姓名,department_name 部门名, d.department_id 部门号 from employees e,departments d where e.department_id = d.department_id; 2.查询90号部门员工的job_id和90号部门的location_id mysql > select job_id 工种号, location_id 区域编号 from employees e,departments d where e.department_id = d.department_id and d.department_id = 90; 3.选择所有有奖金的员工的last_name,department_name,location_id,city mysql > select last_name 姓名,d.department_name 部门名,l.location_id 区域号,city 城市名 from employees e,departments d,locations l where e.department_id = d.department_id and d.location_id = l.location_id and commission_pct is not null; 4.选择city在Toronto工作的员工的last_name,job_id department_id ,department_name mysql > select last_name 姓名,job_id 工种号,d.department_id 部门编号,department_name 部门名 from employees e,departments d,locations l where e.department_id = d.department_id and d.location_id = l.location_id and city = 'Toronto'; 5.查询每个工种,每个部门的部门名,工种名和最低工资 mysql > select department_name 部门名,job_title 工种名, min(salary) 最低工资 from employees e,departments d,jobs j where e.department_id = d.department_id and e.job_id = j.job_id group by j.job_id,d.department_id; 6.查询每个国家下个部门个数大于2的国家编号 mysql > select count(*) 部门个数,country_id 国家编号 from departments d,locations l where d.location_id = l.location_id group by country_id having count(*) > 2; 7.选择指定员工的姓名,员工号以及他的管理者的姓名和员工号,结果类似于下面的格式 employees Emp# manager mgr# kochhar 101 King 100 mysql > select e1.last_name 员工姓名,e1.employee_id 员工号,e2.last_name 管理者姓名,e2.employee_id 管理者编号 from employees e1,employees e2 wherw e1.manager_id = e2.employee_id and e1.last_name = 'kochhar'; SQL99 1.语法: select 查询列表 from 表1 别名 [连接类型] join 表2 别名 on 连接条件 [where 筛选条件] [ group by 分组] [having 筛选条件] [ order by 排序列表] 2.连接类型 1.内连接 inner 2.外连接 左外(left [outer]) 右外(right [outer])全外(full [outer]) 3.交互连接 cross 3.内连接 1.语法: select 查询列表 from 表1 别名 inner join on 连接条件 ...... 2.等值 分类: 1.等值 案例:查询员工名,部门名 mysql > select concat(first_name,last_name) 员工姓名,department_name 部门名 from employees e inner join departments d on e.department_id = d.department_id; 案例:查询名称中包含e的员工名和工种名---添加条件 mysql > select concat(first_name,last_name) 员工名,job_title 工种名 from employees e inner join jobs j on e.job_id = j.job_id where concat(first_name,last_name) like '%e%'; 案例:查询部门个数 > 3的城市名和部门个数---添加分组+筛选 mysql > select count(*) 部门个数,city 城市名 from departments d inner join locations l on d.location_id = l.location_id group by city having count(*) > 3; 案例:查询那个部门的员工个数 > 3的部门名和员工个数,并按个数降序---添加排序 mysql > select count(*) 员工个数, department_name 部门名 from employees e inner join departments d on e.department_id = d.department_id group by department_name having 员工个数 > 3 order by 员工个数 desc; 案例:查询员工名,部门名,工种名,并按部门名降序----多表联合查询 mysql > select concat(last_name,first_name) 员工名,department_name 部门名,job_title 工种名 from employees e inner join departments d inner join jobs j on e.department_id = d.department_id and e.job_id = j.job_id order by department_name desc; 这个案例这样做是错的 mysql > select concat(last_name,first_name) 员工名,department_name 部门名,job_title 工种名 from employees e inner join departments d on e.department_id = d.department_id ininer jobs j on e.job_id = j.job_id order by department_name desc; 先蓝色部分得到交集,再用这交集的部分与红色的部分进行交集,得到结果 特点: 1.可以添加排序,分组,筛选 2.inner可以省略 3.筛选条件咋where之后,连接条件在on之后,提高了代码的复用性,用于阅读 4.inner join连接和sql92语法中的等值效果是一样的,都是查询交集 2.非等值连接 案例:查询员工的工资级别 mysql > select concat(first_name,last_name) 员工姓名,salary 工资,grade_level as 员工的工资级别 from employees e inner join job_grades on salary between lowest_sal and highest_sal; 案例:查询工资级别的个数大于20,并且按工资级别降序 mysql > select count(*) 个数 from employees inner join job_grades on salary between lowest_sal and highest_sal group by grade_level having count(*) > 20 order by grade_level; 3.自连接 案例:查询员工名,上级的名字 mysql > select concat(e1.first_name,e2.last_name) 员工名字,concat(e2.first_name,e2.last_name) 上级名字 from employees e1 inner join employees e2 on e1.manager_id = e2.employee_id; 4.外连接 引入:查询没有男朋友的女神名 应用场景:用于查询一个表中有,另一个表中没有的记录 特点: 1.外连接的查询结果为主表中所有的记录 1.如果从表中有和它匹配的,则显示匹配的值 2.如果从表中没有和它匹配的,则显示null 3.外连接查询的结果 = 内连接结果 + 主表中有而从表中没有的记录 2.左外---左边的表是主表,右外---右边的表示主表,即要查询的信息来自哪个表,那个表就是主表 3.左外和右外交换两个表的顺序,可以实现同样的效果 案例;查询男朋友不在男神表中的女神名 mysql > use girls; msyql > SELECT b.name 女神名,bo.boyName FROM beauty b LEFT JOIN boys bo ON b.`boyfriend_id` = bo.`id` WHERE bo.`id` IS NULL; 总结: 案例:查询哪个部门没有员工 mysql >select count(*) 员工个数,department_id 部门编号 from employees group by department_id having count(*) = 0;--- 完全错误,完全不理解题意 mysql > select d.department_id 部门编号,employee_id 员工编号 from departments d left join employees e on d.department_id = e.department_id where employee_id is null; 5.全外连接 全外连接 = 内连接的结果 + 表1中有但表2中没有 + 表1中没有但表2中有 6.交叉连接--笛卡尔积 A = {1,2} B = {a,b,c} A * B = {(1,a),(1,b),(1,c),(2,a),(2,b),(2,c)} 案例 1.查询编号 > 3的女神名的男朋友的信息,如果有则列出详细,如果没有,则null填充 mysql > use grils; mysql > select b.name 女神姓名, bo.* from beauty b left join boys bo on b.boyfriend_id = bo.id where b.id > 3; 1.查询哪个城市没有部门 mysql > select city 城市,department_name 部门名 from departments d right join locations l on d.location_id = l.location_id where d.department_id is null; 3.查询部门名为SAL或IT的员工信息 mysql >select department_name 部门名,e.* from departments d left join employees e on d.department_id = e.department_id where department_name in ('SAL','IT');