MySQL
一、常见的SQL函数
1、length(str)
:获取参数的字节数
- a)
length()
: 单位是字节,utf8编码下,一个汉字三个字节,一个数字或字母一个字节。gbk编码下,一个汉字两个字节,一个数字或字母一个字节。 - b)
char_length()
:单位为字符,不管汉字还是数字或者是字母都算是一个字符。
注意: varchar(20)
中的20表示字节数,如果存放utf-8
编码的话只能放6个汉字。varchar(n)
,这里的n表示字节数。
MySQL 5.0.3 之后: varchar(20)
表示字符数,不管什么编码,既汉字也能放20个。0-65532也就是最多占65532字节。
varchar(n)
这里的n表示字符数,比如varchar(200)
,不管是英文还是中文都可以存放200个。
mysql> select length('abcd');+----------------+| length('abcd') |+----------------+| 4 |+----------------+1 row in set (0.00 sec)
mysql> select first_name,char_length(first_name) as '字符个数' from employees;+-------------+--------------+| first_name | 字符个数 |+-------------+--------------+| Steven | 6 || Neena | 5 || Lex | 3 || Alexander | 9 || Bruce | 5 |
mysql> select length('小白abc');+---------------------+| length('小白abc') |+---------------------+| 9 |+---------------------+1 row in set (0.00 sec)
2. concat(str1,str2,...)
:连接字符串
mysql> select concat(last_name,'--',first_name) as 姓名 from employees;
3. 字符串替换insert
,replace
- (1)
insert(str1,x,len,'str2')
字串替换函数 str1返回的字串,字串字符的起始位置重1开始,当x为0值或负值(-2)时返回原始字符串;len是字串长度;str2是替换的字串
mysql> select insert(first_name,1,4,'000') from employees;mysql> select insert('zhangsan',1,5,'li');+-----------------------------+| insert('zhangsan',1,5,'li') |+-----------------------------+| lisan |+-----------------------------+1 row in set (0.00 sec)
- (2)
replace
(‘目标字符串’,‘被替换子串’,‘用于替换的新串’)替换
mysql> select replace('目标字符串','字符','哈哈');+----------------------------------------------+| replace('目标字符串','字符','哈哈') |+----------------------------------------------+| 目标哈哈串 |+----------------------------------------------+1 row in set (0.00 sec)
4、upper(str)
:小写字母变大写;lower(str)
:大写字母变小写;
mysql> select UPPER('hehe');+---------------+| upper('hehe') |+---------------+| HEHE |+---------------+1 row in set (0.00 sec)
mysql> select lower('XIXI');+---------------+| lower('XIXI') |+---------------+| xixi |+---------------+1 row in set (0.00 sec)
5.字符截取left right substr
- (1)
substr == substring SUBSTR(str,pos,len)
第一个数字是开始截取的索引值,第二个数数截取的长度 -
- 案例:截取字符串,从第4个字符(包含)开始到最后
mysql> select substr('目标字符串',4) as out_put;+---------+| out_put |+---------+| 符串 |+---------+1 row in set (0.00 sec)
-
- 案例:截取字符串,从第二个开始接到第三个
mysql> select substr('目标字符串',2,1) as out_put;+---------+| out_put |+---------+| 标 |+---------+1 row in set (0.00 sec)
- (2)
left('str1',4)
从左开始截取四个字符 - (3)
right('str1',4)
从右开始截取四个字符
6、trim
删除字符串左右两侧的空格,作用是去掉字符串前后的空格,中间空格去不掉
mysql> select trim(' hello world ');+-------------------------+| trim(' hello world ') |+-------------------------+| hello world |+-------------------------+1 row in set (0.00 sec)
去掉前后两端的其他字符:
mysql> select trim('a' from 'abcasadefa'); 将a字符从指定的字符串中剔除(首和末尾)+-----------------------------+| trim('a' from 'abcasadefa') |+-----------------------------+| bcasadef |+-----------------------------+1 row in set (0.00 sec)
7.判断字符第一次出现的位置 instr locate
- (1)
instr
(‘源字符串’,‘子字符串’):作用返回子字符串子源字符串里的起始索引.
mysql> select instr('目标字符串','字符'); //判断某字符在字符串中的第一次出现的位置+--------------------------------------+| instr('目标字符串','字符') |+--------------------------------------+| 3 |+--------------------------------------+1 row in set (0.00 sec)
返回结果3, 如果找不到返回0
(2)mysql> select locate('a','dfdakfhsdf'); a字符在字符串中第一次出现的位置+--------------------------+| locate('a','dfdakfhsdf') |+--------------------------+| 4 |+--------------------------+1 row in set (0.00 sec)
8.lpad字串填充
lpad
(‘目标字符串’,10,‘填充字符’); 将填充字符填充到目标字符的左边,补足10个
mysql> select lpad('哈哈哈',10,'*');+--------------------------+| lpad('哈哈哈',10,'*') |+--------------------------+| *******哈哈哈 |+--------------------------+1 row in set (0.00 sec)
mysql> select rpad('哈哈哈',10,'*');+--------------------------+| rpad('哈哈哈',10,'*') |+--------------------------+| 哈哈哈******* |+--------------------------+1 row in set (0.00 sec)
9.反显示字串 reverse
mysql> select reverse('dfdakfhsdf');+-----------------------+| reverse('dfdakfhsdf') |+-----------------------+| fdshfkadfd |+-----------------------+1 row in set (0.00 sec)
10.比较两个字串顺序,strcmp
如果这两个字符串相等返回0,如果第一个参数是根据当前的排序小于第二个参数顺序返回-1,否则返回1。
mysql> select strcmp('a','b')-> ;+-----------------+| strcmp('a','b') |+-----------------+| -1 |+-----------------+1 row in set (0.00 sec)
11.正则匹配regexp
mysql> select first_name from employees where first_name regexp 'Su?an'; +------------+| first_name |+------------+| Susan |+------------+1 row in set (0.00 sec)
? 前一个字符字符匹配 0 次或 1 次^字符串的开始$字符串的结尾.任何单个字符 .{3}[. . . ]在方括号内的字符列表[^ . . . ]非列在方括号内的任何字符p1 | p2 | p3交替匹配任何模式p1,p2或p3*零个或多个前面的元素+前面的元素的一个或多个实例{n}前面的元素的n个实例{m , n}m到n个实例前面的元素
char_length substr
1、数学函数
1.round
四舍五入
mysql> select round(1.45);+-------------+| round(1.45) |+-------------+| 1 |+-------------+1 row in set (0.00 sec)
mysql> select round(1.567,2);+----------------+| round(1.567,2) |+----------------+| 1.57 |+----------------+1 row in set (0.00 sec)
2.ceil
向上取整
mysql> select ceil(-1.3);+------------+| ceil(-1.3) |+------------+| -1 |+------------+1 row in set (0.00 sec)
mysql> select ceil(1.3);+-----------+| ceil(1.3) |+-----------+| 2 |+-----------+1 row in set (0.00 sec)
3.floor
向下取整
mysql> select floor(1.3);+------------+| floor(1.3) |+------------+| 1 |+------------+1 row in set (0.00 sec)
mysql> select floor(-1.8);+-------------+| floor(-1.8) |+-------------+| -2 |+-------------+1 row in set (0.00 sec)
4.truncate
截断小数点开始截取
mysql> select truncate(1.65,1);+------------------+| truncate(1.65,1) |+------------------+| 1.6 |+------------------+1 row in set (0.00 sec)
mysql> select truncate(1.6565,1);+--------------------+| truncate(1.6565,1) |+--------------------+| 1.6 |+--------------------+1 row in set (0.01 sec)
mysql> select truncate(1.6565,2);+--------------------+| truncate(1.6565,2) |+--------------------+| 1.65 |+--------------------+1 row in set (0.00 sec)
5.mod
取余
mysql> select mod(10,3);+-----------+| mod(10,3) |+-----------+| 1 |+-----------+1 row in set (0.00 sec)
2、日期函数
1.now
用户返回当前日期时间
mysql> select now();+---------------------+| now() |+---------------------+| 2021-08-02 14:37:15 |+---------------------+1 row in set (0.00 sec)
2.curdate
返回当前系统日期,没有时间部分
mysql> select curdate();+------------+| curdate() |+------------+| 2021-08-02 |+------------+1 row in set (0.00 sec)
3.curtime
返回当前系统时间,没有日期部分
mysql> select curtime();+-----------+| curtime() |+-----------+| 14:38:32 |+-----------+1 row in set (0.00 sec)
4.可以单独获取年/月/日
mysql> select year(now());+-------------+| year(now()) |+-------------+| 2021 |+-------------+1 row in set (0.00 sec)
mysql> select year('2021-1-1');+------------------+| year('2021-1-1') |+------------------+| 2021 |+------------------+1 row in set (0.00 sec)
mysql> select month(now());+--------------+| month(now()) |+--------------+| 8 |+--------------+1 row in set (0.00 sec)
mysql> select day(now());+------------+| day(now()) |+------------+| 2 |+------------+1 row in set (0.00 sec)
hour minute second
一样
5. 日期格式转换
mysql> select str_to_date('2021-08-02 10:20:30','%Y-%m-%d %H:%i:%s');+--------------------------------------------------------+| str_to_date('2021-08-02 10:20:30','%Y-%m-%d %H:%i:%s') |+--------------------------------------------------------+| 2021-08-02 10:20:30 |+--------------------------------------------------------+1 row in set (0.00 sec)
mysql> select date_format(now(),'%y-%m-%d');+-------------------------------+| date_format(now(),'%y-%m-%d') |+-------------------------------+| 21-08-02 |+-------------------------------+1 row in set (0.00 sec)
案例:查询入职日期是1992-4-3的员工信息:
mysql> select * from employees where hiredate='1992-4-3';mysql> select * from employees where hiredate=STR_TO_DATE('1992 4 3','%Y %m %d');
3、分组函数(聚合函数)
分组函数和前面讲的函数不同在于,前面的对内容本身的处理,而分组函数的主要功能是统计
常用的分组函数sum , avg , max , min , count
mysql> select sum(salary) as 单月所发总工资 from employees;+-----------------------+| 单月所发总工资 |+-----------------------+| 691400.00 |+-----------------------+1 row in set (0.00 sec)
mysql> select avg(salary) as 单月所发平均工资 from employees;+--------------------------+| 单月所发平均工资 |+--------------------------+| 6461.682243 |+--------------------------+1 row in set (0.00 sec)
mysql> select max(salary) as 单月所发最多工资 from employees;+--------------------------+| 单月所发最多工资 |+--------------------------+| 24000.00 |+--------------------------+1 row in set (0.00 sec)
mysql> select min(salary) as 单月所发最少工资 from employees;+--------------------------+| 单月所发最少工资 |+--------------------------+| 2100.00 |+--------------------------+1 row in set (0.00 sec)
mysql> select count(*) as 总人数 from employees;+-----------+| 总人数 |+-----------+| 107 |+-----------+1 row in set (0.05 sec)
mysql> select count(salary) from employees;+---------------+| count(salary) |+---------------+| 107 |+---------------+1 row in set (0.00 sec)
mysql> select count(distinct salary) from employees;+------------------------+| count(distinct salary) |+------------------------+| 57 |+------------------------+1 row in set (0.00 sec)
4、流程控制函数
1.if
函数
mysql> select if('10>1','大','小');+------------------------+| if('10>1','大','小') |+------------------------+| 大 |+------------------------+1 row in set, 1 warning (0.00 sec)
2.case
函数
case 要判断的字段或表达式when case的结果是常量1 then 要显示的值1(或语句1;)when case的结果是常量2 then 要显示的值2(或语句2;)......else case的结果都不前面的时候显示;end 结束
案例:员工表中, 部门号是30,显示的工资是1.1倍
部门号是50,显示的工资是1.2倍
其他显示原工资
mysql> select salary as 原工资,department_id, -> case department_id -> when 30 then salary*1.1 -> when 50 then salary*1.2 -> else salary -> end as 新工资 -> from employees;+-----------+---------------+-----------+| 原工资 | department_id | 新工资 |+-----------+---------------+-----------+| 24000.00 | 90 | 24000.00 || 17000.00 | 90 | 17000.00 || 17000.00 | 90 | 17000.00 || 9000.00 | 60 | 9000.00 || 6000.00 | 60 | 6000.00 |
多重if
casewhen 条件1 then 要显示的值1(或语句1;)when 条件2 then 要显示的值2(或语句2;)......else 前面的条件都不符合时候显示;end 结束
mysql> select salary, -> case -> when salary>20000 then 'A级工资' -> when salary>10000 then 'B级工资' -> else 'C级工资' -> end as 工资等级 -> from employees;+----------+--------------+| salary | 工资等级 |+----------+--------------+| 24000.00 | A级工资 || 17000.00 | B级工资 || 17000.00 | B级工资 |
综合练习:
查询first_name字段字符长度小于字节长度的所有first_name;
mysql> select first_name,char_length(first_name) as '字符',length(first_name) as '字节' from emp where char_length(first_name) < length(first_name);
二、where条件查询和order by排序
select column_name from table_Name;select column_name from table_Name where group byhavingorder bylimit
where条件查询
语法 : select 查询列表 from 表名称 where 筛选条件
**按照条件表达式来筛选:**条件运算符: > , < , = , != / <>, >= , <=
按照逻辑表达式筛选逻辑运算符:and , not , or
模糊查询:% _ , like , between…and , in , is null ,is not null,regexp() .任意单个字符 * 匹配前一个字符任意次 ?匹配任意字符0或1次
条件表达式
案例:查询员工工资大于12000的员工有哪些?
mysql> select * from employees where salary > 12000;
案例:查询部门编号不等于90号的员工名和部门编号:
mysql> select concat(last_name,first_name) as 姓名, department_id from employees where department_id<>90;
逻辑表达式
案例:工资在10000到20000之间到员工名,工资和奖金
mysql> select last_name,salary,commission_pct from employees where salary>=10000 and salary<=20000;
案例:查询部门编号不是在90到110之间的,或者工资高于15000的员工信息
mysql> select * from employees where department_id<90 or department_id>110or salary>15000;select * from employees where not(department_id<90 and department_id>110) or salary>15000;
模糊查询:
likebetween andinis null | is not null
like
:
案例:查询员工名中包含了"a"字符的所有员工的信息
select * from employees where last_name like '%a%';
%:通配符,表示任意多个字符,也可表示0个字符,
_:任意一个字符;
案例:查询第三个字符为n或第五个字符为l的员工信息
mysql> select * from employees where last_name like '__n_l%';
案例:查询员工信息表中员工名第二个字符是"_"的员工信息
mysql> select * from employees where last_name like '_\_%'; _ \_mysql> select * from employees where last_name like '_&_%' escape '&'; #推荐写法escape '&':说明&这个符号是转义字符
between and
:
案例:查询员工工资中10000到20000之间到员工信息
mysql> select * from employees where salary>=10000 and salary<=20000;mysql> select * from employees where salary between 10000 and 20000;
注意: 使用between and
- 1.可以简洁sql语句
- 2.并且包含临界值
- 3.临界值不能调换位置,小的在左边,大的值在右边.
in
:(列表值)
案例:查询员工的工种编号是 it_prog,ad_vp,ad_pres中任意一个的员工信息
select * From employees where job_id='it_prog' or job_id='ad_vp' or job_id='ad_pres';select * from employees where job_id in ('it_prog','ad_vp','ad_pres');select * from employees where job_id Not in ('it_prog','ad_vp','ad_pres');select * from employees lwhere job_id in ('it_prog','ad_vp','ad_pres',null);select * from employees where job_id not in ('it_prog','ad_vp','ad_pres',null);is null | is no null:
案例:查询没有奖金率的员工信息
mysql> select * from employees where commission_pct is null;
查询奖金率的就取反:
mysql> select * from employees where commission_pct is not null;
注意: commission_pct=null
这个写法不能判断null值
is not
也不能换成<>不等号.
<=>
判断空值 is null
mysql> select * from employees where commission_pct <=>null;
排序查询
语法: select 查询列表 from 表 where 条件 order by 排序字段列表 asc | desc;
案例:查询所有员工信息,要求工资从大到小排列:
mysql> select * from employees order by salary desc;
- descend:降序
- ascend:升序
反过来从小到大排列:
mysql> select * from employees order by salary asc;mysql> select * from employees order by salary; asc 可以省略,默认升序
案例:查询部门编号大于等于90的员工信息,按照入职时间的先后排序
mysql> select * from employees where department_id>=90 order by hiredate asc;
案例:实现按表达式排序:按年薪的高低显示员工信息
select last_name,department_id,salary*12*(1+ifnull(commission_pct,0)) as 年薪 from employees order by salary*12*(1+ifnull(commission_pct,0)) desc;select last_name,department_id,(salary+ifnull(commission_pct,0))*12 年薪 from employeesorder by (salary+ifnull(commission_pct,0))*12 desc;select *,salary*12*(1+ifnull(commission_pct,0)) as 年薪 from employees order by 年薪 desc;
案例:使用函数来排序:按姓名的长度显示员工信息
mysql> select *,length(last_name) as 姓名的长度 from employees order by length(last_name) desc;mysql> select *,length(last_name) as 姓名的长度 from employees order by 姓名的长度 desc;
案例:实现多字段排序:查询员工信息,首先用工资高低排序,工资一样的在按员工id大到小排序
mysql> select * from employees order by salary desc,employee_id desc;
查询employees表中所有员工的姓名以及薪资并将每人薪资+1000;
查询employees表显示每位员工薪资的位数;
注意: ceil()取整 或floor()
查询employees表中first_name和last_name连接显示并标记为’姓名’; concat
select concat(first_name,'-',last_name) as 姓名 from employees;
查询员工表中的job_id类型有哪些;
select distinct job_id from employees;
查询每位员工电话号的后四位数字;
select right(phone_number,4) from employees;
三、分组统计
分组查询:
group by关键字实现分组,group by放在where条件语句之后,order by放置中group by的后面,后面跟上having关键字,总体的循序先后为:
where条件group by 分组语句having 分组的条件order by排序语句
where条件是针对所有记录的,having条件只是局限的针对每一组的记录的
分组查询语法:
select列(这个列要求必须只能是group by的后面字段),分组函数()from表名where筛选条件(针对表的所有记录)group by分组字段列表having(只能配合group by使用)与分组有关的筛选条件(针对分组后的每组内记录)order by排序
案例:查询每个工种的最高工资
mysql> select max(salary),job_id from employees group by job_id;
案例:查询每个地方的部门个数
mysql> select count(*),location_id from departments group by location_id;
案例:查询每个部门每个工种的员工的平均工资
mysql> select count(*) 个数,avg(salary),department_id,job_id from employees group by department_id,job_id;
(部门号和工种号都相同的员工分一组)
案例:查询员工邮箱里包含"a"字母的,每个部门的平均工资
mysql> 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
案例:查询部门的员工个数>5的,并显示所有部门的员工数
- 1)查询每个部门的员工个数
mysql> select count(*) c,department_id from employees group by department_id;
- 2)在第一步的结果中找那个部门的员工个数>5
mysql> select count(*) c,department_id from employees group by department_id having c>5; (聚合函数的结果条件过滤)
案例:查询的没有奖金的每个领导手下员工的最高工资且最高工资工资大于12000,并且按升序排序。
- 1)首先查询每个领导手下没有奖金的
mysql> select max(salary) 最高工资,manager_id from employees where commission_pct is null group by manager_id;
- 2)在1点结果中在选工资大于12000
mysql> select max(salary) 最高工资,manager_id from employees where commission_pct is null group by manager_id having 最高工资>12000;
mysql> select max(salary) maxsalary,manager_idfrom employeeswhere commission_pct is nullgroup by manager_idhaving maxsalary>12000order by maxsalary;
四、多表关联查询
1、交叉连接CROSS
将两张表或多张表联合起来查询,这就是连接查询。交叉连接返回的结果是被连接的两个表中所有数据行的笛卡儿积。
笛卡尔积是必须要知道的一个概念。在没有任何限制条件的情况下,两表连接必然会形成笛卡尔积。(如表1 m行a列,表2 n行b列,则无条件连接时则会有m*n,a+b列。)交叉连接查询在实际运用中没有任何意义
注意: 连接条件必须是唯一字段,如果非唯一字段则会产生笛卡尔积。
\>select * from 表1,表2;
2、内连接inner
指连接结果仅包含符合连接条件的行,参与连接的两个表都应该符合连接条件。
\>select * from 表1,表2 where 表1.字段=表2.字段;\>select * from employees e,departments d where e.department_id=d.department_id;
- 1)等值连接:表之间用=连接
案例:查询员工名和对应的部门名
mysql> select last_name,department_name from employees,departments where employees.department_id=departments.department_id;
可以使用别名
mysql> select last_name,department_name from employees e,departments d where e.department_id=d.department_id;
案例:查询有奖金的员工名以及所属部门名:
mysql> select last_name,department_name from employees e,departments d where e.department_id=d.department_id and e.commission_pct is not null;
案例:查询每个城市的部门个数
mysql> select count(*) as 个数 ,city from departments d,locations l where d.location_id=l.location_id group by city;
案例:查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资
mysql> select d.department_name,d.manager_id,min(e.salary)from departments d,employees ewhere d.department_id = e.department_idand e.commission_pct is not nullgroup by d.department_name,d.manager_id;
注意: sql中select后面的字段必须出现在group by后面,或者被聚合函数包裹,不然会抛出以下的错误
sql_mode=only_full_group_by
案例:查询每个工种的工种名和员工个数,并且按照员工个数排序降序
mysql> select job_title,count(*) from employees e,jobs j where e.job_id=j.job_id group by job_title order by count(*) desc;
案例:查询员工名,部门名和所在城市名
mysql> select last_name,department_name,city from employees e,departments d,locations l where e.department_id=d.department_id and d.location_id=l.location_id;
SELECT column_listFROM t1INNER JOIN t2 ON join_condition1INNER JOIN t3 ON join_condition2...WHERE where_conditions;
- 2)自连接:相当于等值连接,只不过是自己连接自己,不像等值连接是两个不同的表之间的;
案例:查询员工名和他的上司的名字
mysql> select e.last_name,m.last_name from employees e,employees m where e.manager_id=m.employee_id;
- 3)非等值连接:等值连接中的等号改成非等号情况
创建一张job_grades工资级别表:
create table job_grades(grade_level varchar(3),lowest_sal int,highest_sal int) ;insert into job_grades values('A' , 1000,2999);insert into job_grades values('B' , 3000,5999);insert into job_grades values('C' , 6000,9999);insert into job_grades values('D' , 10000,14999);insert into job_grades values('E' , 15000,24999);insert into job_grades values('F' , 25000,40000);
案例:查询员工的工资和工资级别
mysql> SELECTsalary,grade_levelFROMemployees e,job_grades jWHEREsalary BETWEEN j.lowest_sal AND j.highest_sal;
select 查询列表from 表1 别名【链接类型】 join 表2 别名on 链接条件where 数据筛选条件;
1.查询员工名和其对应所属的部门名
select last_name,department_namefrom employees einner join departments don e.department_id = d.department_id;
2.查询名字中包含e字母的员工名和其对象的部门名
select last_name,department_namefrom employees einner join departments don e.department_id = d.department_idwhere last_name like '%e%';
3.查询所在部门个数大于3的城市名和部门个数
select count(d.department_id) count,l.cityfrom departments dinner join locations lon d.location_id = l.location_idgroup by l.cityhaving count>3;
4.查询员工个数大于3的部门名和员工个数,降序排序
SELECT d.department_name,COUNT(e.employee_id) cFROM employees eINNER JOIN departments dON e.department_id=d.department_idGROUP BY d.department_nameHAVING c>3ORDER BY c DESC;
5.查询员工名以及对应的工种名和部门名,按部门名降序排序
select e.last_name,j.job_title,d.department_namefrom employees einner join departments don e.department_id = d.department_idinner join jobs jon e.job_id=j.job_idorder by d.department_name desc;
案例:查询员工的工资和工资级别
SELECTsalary,grade_levelFROMemployees eINNER JOINjob_grades gONe.salary BETWEEN g.lowest_sal AND g.highest_sal;
案例: 查询员工的名和其对应的直属领导
SELECTe.last_name employee_name,m.last_name manager_nameFROMemployees eINNER JOINemployees mONe.manager_id=m.employee_id;
3、外连接:outer
外连不但返回符合连接和查询条件的数据行,还返回不符合条件的一些行。外连接分三类:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)和全外连接(FULL OUTER JOIN)。
三者的共同点是都返回符合连接条件和查询条件(即:内连接)的数据行。不同点如下:
- 左外连接还返回左表中不符合连接条件单符合查询条件的数据行。
- 右外连接还返回右表中不符合连接条件单符合查询条件的数据行。
- 全外连接还返回左表中不符合连接条件单符合查询条件的数据行,并且还返回右表中不符合连接条件单符合查询条件的数据行。全外连接实际是上左外连接和右外连接的数学合集(去掉重复),即“全外=左外 UNION 右外”。
说明: 左表就是在“(LEFT OUTER JOIN)”关键字左边的表。右表当然就是右边的了。在三种类型的外连接中,OUTER 关键字是可省略的。
两张表:ta:id,age字段,tb:id,name,ta_id
create table ta(id int,age int);create table tb(id int,name varchar(4),ta_id int);insert into ta(id,age) values(1,12);insert into ta(id,age) values(2,22);insert into ta(id,age) values(3,32);insert into ta(id,age) values(4,42);insert into ta(id,age) values(5,52);insert into ta(id,age) values(6,62);insert into tb(id,name,ta_id) values(1,'任波涛',2);insert into tb(id,name,ta_id) values(2,'田兴伟',1);insert into tb(id,name,ta_id) values(3,'唐崇俊',3);insert into tb(id,name,ta_id) values(4,'夏铭睿',8);insert into tb(id,name,ta_id) values(5,'包琪',1);insert into tb(id,name,ta_id) values(6,'夏雨',10);insert into tb(id,name,ta_id) values(7,'夏铭雨',10);insert into tb(id,name,ta_id) values(8,'白芳芳',6);
**外连接:**有这样的场景,在ta和tb两表中查询没有对应年龄数据的学生姓名和年龄
SELECTtb.name,ta.ageFROMtbINNER JOINtaONtb.ta_id=ta.idWHEREta.id IS NULL;
掌握外连接知识点:
- 1.外连接的查询结果为主表中有的所有记录
外表有对应数据,结果记录上显示对应数据
外表中没有对应的数据,结果记录上填充null -
- 和内连接的区别:
-
- 内连接: 当从表没有记录的时候,主、从表的记录都丢掉!
-
- 外连接: 当从表没有记录的时候,会保留主表的记录,对应从表null
- 2.左外连接:left join左边的是主表,右外连接right join 右边的是主表
- 3.左外连接和右外连接上互通的所以掌握一个就好!
**解决:**在ta和tb两表中查询没有对应年龄数据的学生姓名和年龄
SELECTtb.name,ta.ageFROMtbLEFT JOINtaONtb.ta_id=ta.idWHEREta.id IS NULL;
案例:查询没有员工的部门
SELECT d.department_id,d.department_name,e.employee_idFROM departments dLEFT JOIN employees eON d.department_id=e.department_idWHERE e.employee_id IS NULL;
全外连接: Oracle、MySQL不支持全连接。可以使用UNION ALL语句来组合左连接和右连接
4、子查询
子查询介绍: 出现在其他语句中的select语句,被包裹的select语句就是子查询或内查询
包裹子查询的外部的查询语句:称主查询语句
比如:
select last_name from employeeswhere department_id in(select department_id from departmentswhere location_id=1700);
子查询分类
1、通过位置来分:
select 后面:仅仅支持标量子查询from 后面:支持表子查询where 或having 后面:支持标量子查询(重要)\列子查询(重要)\行子查询(用的较少)exists 后面(相关查询):支持表子查询
按结果集的行列数不同分类:
标量子查询(结果集只有一行一列)列子查询(结果集只有一列但有多行)行子查询(结果集只有一行但有多列)表子查询(结果集多行多列)
子查询特点:
子查询放在小括号内子查询一般放在条件的右侧标量子查询,一般搭配着单行操作符来使用(> < >= <= <> =)列子查询,一般搭配着多行操作符使用:in any/some all子查询的执行顺序优先于主查询(select后的子查询存在例外)
- 1.where后面的标量子查询
案例:查询工资比Abel这个人的高的员工信息
select * from employeeswhere salary>(select salaryfrom employeeswhere last_name='Abel');
- 2.查询job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
select last_name,job_id,salaryfrom employeeswhere job_id=(select job_id from employeeswhere employee_id=141 ) and salary>(select salaryfrom employees where employee_id=143);
(这个案例说明一个主查询里可以放很多个子查询)
- 3.子查询里用到分组函数:查询公司工资最少的员工的last_name,job_id和salary
select last_name,job_id,salary from employeeswhere salary=(select min(salary) from employees);
- 4.用到having的子查询:查询最低工资大于50号部门最低工资的部门id和其最低工资
select department_id , min(salary) from employeesgroup by department_idhaving min(salary)>(select min(salary) from employees where department_id=50);
-
- where后面的列子查询(多行子查询)
首先来看一下多行操作符:in/not in:等于列表中的任意一个a in(10,20,30); 可以替换 a=10 or a=20 or a=30;any/some:和子查询返回的某一个值比较a > any(10,20,30); 可以替换 a > min(10,20,30);all:和子查询返回的所有值比较a > all(10,20,30); 可以替换 a > max(10,20,30);a >10 and a>20 and a>30
案例:返回location_id是1400或1700的部门中的所有员工的名字
select last_name from employeeswhere department_id in (select department_id from departmentswhere location_id in (1400,1700));
案例:查询其他工种中比job_id为’IT_PROG’的员工某一工资低的员工的员工号,姓名,job_id和salary
SELECT employee_id,last_name,job_id,salary FROM employeesWHERE salary < ANY(SELECT distinct salary FROM employees WHERE job_id='IT_PROG') and job_id<>'IT_PROG';
案例:查询其他工种中比job_id为’IT_PROG’的员工所有工资低的员工的员工号,姓名,job_id和salary
SELECT employee_id,last_name,job_id,salary FROM employeesWHERE salary < all(SELECT distinct salary FROM employees WHERE job_id='IT_PROG') and job_id<>'IT_PROG';
-
- where后面的行子查询(一行多列)
案例:查询员工编号最小并且工资最高的员工信息
select * from employeeswhereemployee_id = (select min(employee_id) from employees)andsalary = (select max(salary) from employees);
下面是行子查询的写法(用的很少,了解就可以):
select * from employeeswhere (employee_id,salary)=(select min(employee_id) , max(salary) from employees);
-
- select 后面(很少用的,可以用前面讲的方法实现):
案例:查询每个部门的部门信息和对应的员工个数(不用连接查询)
select d.*,(select d.department_name count(*) from employees ewhere d.department_id=e.department_id) from departments d;select *,(select count(*) from employees e,departments dwhere d.department_id=e.department_id group by d.department_name ) tempfrom departments temp;
-
- from后面的子查询:
案例:查询每个部门的平均工资等级
select avg(salary),department_id from employees group by department_id;SELECTavg_res.avgs,avg_res.department_id,g.grade_levelFROM(SELECT AVG(salary) avgs,department_idFROM employees GROUP BY department_id) avg_res,job_grades gWHEREavg_res.avgs BETWEEN g.lowest_sal AND g.highest_sal;
-
- exists后面(相关子查询)
exists的作用是: 判断子查询有没有结果的存在
案例: select exists(select employee_id from employees); 返回的结果:1;
语法:
select exists(完整的子查询); 子查询有结果返回1,没有结果返回0;
案例:查询有员工的部门名
select department_name from departments dwhere exists(select * from employees e where d.department_id=e.department_id );
注意: 能用exists的绝对能用前面讲过的in来实现,所以exists很少使用
select department_name from departments dwhere d.department_id in (select department_id from employees);
五、分页查询
分页查询:
数据记录条数过多的时候,需要分页来显示
语法:
select 查询字段 from 表名where ....等等前面学过的所有写法group byhavingorder bylimit offset(开始记录索引,是从0开始的),size(要取出的条数);
案例: 查询前5条员工数据
mysql> select * from employees limit 0,5;mysql> select * from employees limit 5;
注意: 如果从第一条开始,这个0可以省略:select * form employees limit 5;
案例:查询第11条到第25条
mysql> select * from employees limit 10,15;
案例:查询有奖金且工资最高的前10名的员工信息
select * from employees where commission_pct is not null order by salary desc limit 10;
分页查询的特点:
limit语句是位置上是要放在比order by语句的还后面,其次中sql执行过程中,limit也是最后去执行的语句.
来源地址:https://blog.csdn.net/weixin_63172698/article/details/133398073