昨日内容回顾
-
表与表之间建关系(外键)
""" 表与表之间最多只有四种关系 一对多 多对多 一对一 没有关系 在确定表与表之间的关系的时候记住一句话 换位思考 """ # 一对多(一对多、多对一都叫 一对多) """ 一对多关系字段放在多的一方 以员工表和部门表 员工表就是多的一方 所以外键字段应该建在员工表里面 """ 站在两张表的基础之上 只有一方成立 那么就是一对多 create table dep( id int primary key auto_increment, dep_name char(16), dep_desc char(32) ); create table emp( id int primary key auto_increment, name char(16), age int, dep_id int, foreign key(dep_id) references dep(id) ) # 多对多 站在两张表的基础之上 双方都成立 那么就是多对多 多对多需要创建第三张关系表来存储两张表的关系,两张表自身没有任何额外字段 """ 以图书表和作者表为例 多对多外键字段放在第三张表中 """ create table book( id int primary key auto_increment, title char(16), price float(10,2) ); create table author( id int primary key auto_increment, name char(16), age int ); create table book2author( id int primary key auto_increment, book_id int, foreign key(book_id) references book(id) on update cascade on delete cascade, author_id int, foreign key(author_id) references author(id) on update cascade on delete cascade ) # 一对一 """ 以用户与用户详情 针对一对一的外键关系 外键字段建在任意一方都可以 但是我们推荐你建在查询频率/使用频率较高的那张表 """ 站在双方的角度都不成立 一对一/没有关系 create table user( id int primary key auto_increment, name char(64) default 'jason', gender enum('male','female','others') default 'male', user_detail_id int unique, foreign key(user_detail_id) references user_detail(id) on update cascade on delete cascade ) create table user_detail( id int primary key auto_increment, phone int, addr char(64) )
-
外键注意事项
1.必须先创建被关联表(dep表) 2.录入数据的时候也是先录入被关联表的数据(dep表) 3.想要有关系的数据同步更新同步删除 create table emp( id int primary key auto_increment, name char(16), age int, dep_id int, foreign key(dep_id) references dep(id) on update cascade on delete cascade )
-
其他需要了解的sql语句操作
主要是针对表的操作 1.修改表名 alter table t1 rename t666; 2.添加字段 alter table t666 add password int; alter table t666 add gender char(4) first; alter table t666 add age int after name; 3.修改字段 alter table t666 modify password bigint; alter table t666 change password pwd int; 4.删除字段 alter table t666 drop pwd;
-
复制表(了解)
""" 我们sql语句执行的结果可以把它看成是一张虚拟表 """ create table t1 select * from t666; # 将t666的数据复制到t1中了 但是没有外键、主键、索引....
-
作业
1.书籍表和出版社表(版权问题一本书不能被多个出版社出版) 一本书能否对应多个出版社 不可以 一个出版社能否对应多本书 可以 一对多 多:书 一:出版社 外键字段建在书的一方 2.文章表和文章分类表(按男女分类...) 一遍文章能够对应多个分类 不可以 一个分类能否对应多个文章 可以 一对多 多:文章 一:分类 外键字段建在文章的一方 3.文章表和文章标签表(一个人可以有多个标签) 一遍文章可以有多个标签 可以 一个标签能否对应多个文章 可以 多对多 需要创建第三张关系表 4.作者表和作者详情表 一对一
今日内容概要
-
单表操作
select from where group by having distinct order by limit ...
-
多表操作
1.子查询 2.联表查询
今日内容详细
前期表及数据准备
create table emp(
id int primary key auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, #一个部门一个屋子
depart_id int
);
# 插入数据
insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values
('jason','male',18,'20170301','张江第一帅形象代言',7300.33,401,1), #以下是教学部
('tom','male',78,'20150302','teacher',1000000.31,401,1),
('kevin','male',81,'20130305','teacher',8300,401,1),
('tony','male',73,'20140701','teacher',3500,401,1),
('owen','male',28,'20121101','teacher',2100,401,1),
('jack','female',18,'20110211','teacher',9000,401,1),
('jenny','male',18,'19000301','teacher',30000,401,1),
('sank','male',48,'20101111','teacher',10000,401,1),
('哈哈','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
('呵呵','female',38,'20101101','sale',2000.35,402,2),
('西西','female',18,'20110312','sale',1000.37,402,2),
('乐乐','female',18,'20160513','sale',3000.29,402,2),
('拉拉','female',28,'20170127','sale',4000.33,402,2),
('僧龙','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬银','female',18,'20130311','operation',19000,403,3),
('程咬铜','male',18,'20150411','operation',18000,403,3),
('程咬铁','female',18,'20140512','operation',17000,403,3);
ps:
select * from emp;
select * from emp\G;
*************************** 16. row ***************************
id: 16
name: 程咬银
sex: female
age: 18
hire_date: 2013-03-11
post: operation
post_comment: NULL
salary: 19000.00
office: 403
depart_id: 3
*************************** 17. row ***************************
"""
如果在windows系统中,插入中文字符,select的结果为空白,可以将所有字符编码统一设置成gbk
将配置文件中所有的编码由原来的utf8换成gbk
然后重启mysql服务端
"""
sql语句书写顺序和执行顺序
select name,salary from emp where id < 5;
# 执行顺序
from 1.先确定从哪张表找数据
where 2.再根据where后面的条件筛选
select 3.再获取指定的字段对应的数据
where筛选
"""
and 与 and连接的条件必须都满足
or 或 or连接的条件满足一个就可以
not 非 not取反
"""
# where后面跟得其实就是筛选条件
# 1.查询id大于等于3小于等于6的数据
select * from emp where id >= 3 and id <= 6 ;
select * from emp where id between 3 and 6; # 随你自己
# 2.查询薪资是20000或者18000或者17000的数据
select * from emp where salary=20000 or salary=18000 or salary=17000;
select * from emp where salary in (20000,18000,17000);
# 3.查询员工姓名中包含o字母的员工姓名和薪资
"""
模糊匹配
关键字 like
特殊符号
% 匹配任意个数的任意字符
_ 匹配一个任意字符
"""
select name,salary from emp where name like '%o%';
mysql> select name,salary from emp where name like '%o%';
+-------+------------+
| name | salary |
+-------+------------+
| jason | 7300.33 |
| tom | 1000000.31 |
| tony | 3500.00 |
| owen | 2100.00 |
+-------+------------+
mysql> select name,salary from emp where name like 'o%';
+------+---------+
| name | salary |
+------+---------+
| owen | 2100.00 |
+------+---------+
mysql> select name,salary from emp where name like '%o';
# 4.查询员工姓名是由四个字符组成的员工姓名与其薪资
select name,salary from emp where name like '%%%%'; 不行!!!
select name,salary from emp where name like '____';
# 5.查询id小于3或者大于6的数据
select * from emp where id < 3 or id > 6;
# 6.查询薪资不在20000,18000,17000的数据
select * from emp where salary not in (20000,18000,17000);
# 7.查询岗位描述为空的员工名与岗位名
select name,post from emp where post_comment=NULL; 没有效果!!!
select name,post from emp where post_comment is NULL;
针对null不能用等号,只能用is
group by分组
"""
聚合函数
max 求最大值
min 求最小值
avg 求平均值
sum 求和
count 统计个数
聚合函数只能在分组之后使用
"""
# 数据分组应用场景:每个部门的平均薪资,男女比例等
"""
将个体按照组 组成一个个的整体
然后就以整体为单位操作
"""
# 1.按部门分组
select * from emp group by post; # group by后面跟什么就按照什么分组
"""
分组之后默认情况下不应该再直接获取到组内单个元素的数据,而是只能获取分组的依据
按照部门分组的话 那么你就只能获取到部门
5.6及之前的版本 没有设置严格模式 分组之后数据随便拿也不报错
5.6之后的版本的 分组之后select后面只能写分组的依据 不能直接写其他字段
"""
set global sql_mode="strict_trans_tables,only_full_group_by";
退出客户端重新进入即可
mysql> select * from emp group by post;
ERROR 1055 (42000): 'day04.emp.id' isn't in GROUP BY
mysql> select name from emp group by post;
ERROR 1055 (42000): 'day04.emp.name' isn't in GROUP BY
mysql> select salary from emp group by post;
ERROR 1055 (42000): 'day04.emp.salary' isn't in GROUP BY
mysql> select post from emp group by post;
+-----------------------------+
| post |
+-----------------------------+
| operation |
| sale |
| teacher |
| 张江第一帅形象代言 |
+-----------------------------+
'''
# 1 获取每个部门的最高工资
select max(salary) from emp group by post;
mysql> select post,max(salary) from emp group by post;
+-----------------------------+-------------+
| post | max(salary) |
+-----------------------------+-------------+
| operation | 20000.00 |
| sale | 4000.33 |
| teacher | 1000000.31 |
| 张江第一帅形象代言 | 7300.33 |
+-----------------------------+-------------+
mysql> select post,max(salary) as '最高薪资' from emp group by post;
+-----------------------------+--------------+
| post | 最高薪资 |
+-----------------------------+--------------+
| operation | 20000.00 |
| sale | 4000.33 |
| teacher | 1000000.31 |
| 张江第一帅形象代言 | 7300.33 |
+-----------------------------+--------------+
mysql> select post as '部门',max(salary) as '最高薪资' from emp group by post;
+-----------------------------+--------------+
| 部门 | 最高薪资 |
+-----------------------------+--------------+
| operation | 20000.00 |
| sale | 4000.33 |
| teacher | 1000000.31 |
| 张江第一帅形象代言 | 7300.33 |
+-----------------------------+--------------+
# 每个部门的最低工资
select post,min(salary) from emp group by post;
# 每个部门的平均工资
select post as '部门', avg(salary) as '平均工资' from emp group by post;
# 每个部门的员工人数
select post as '部门',count(id) as '员工人数' from emp group by post;
# 3.查询分组之后的部门名称和每个部门下所有的学生姓名
select post,group_concat(name) from emp group by post;
select post,group_concat(name,'_NB') from emp group by post;
select post,group_concat(name,':',salary) from emp group by post;
"""
数据的拼接操作
分组之后可以使用
group_concat
分组之前可以使用
concat
"""
# 4.补充concat(不分组时用)拼接字符串达到更好的显示效果 as语法使用
select name as 姓名,salary as 薪资 from emp;
select concat("NAME: ",name) as 姓名,concat("SAL: ",salary) as 薪资 from emp;
分组注意事项
select id,name,age from emp where max(salary) > 3000; 不能这么用
select max(salary) from emp;
不分组的情况下默认整体就是一组 可以在select的后面使用聚合函数
8、统计各部门年龄在30岁以上的员工平均工资
# 1.先拿到所有年龄大于30岁的员工数据
select * from emp where age > 30;
# 2.再按照部门分组 得到年龄大于30岁的部门
select post,group_concat(name) from emp where age > 30 group by post;
# 最终完成
select post,avg(salary) from emp where age > 30 group by post;
having分组之后过滤
"""
where
having
两者的功能都是筛选数据 是一样的
但是两者的使用场景不一样
where分组之前使用
having分组之后使用
"""
1、统计各部门年龄在30岁以上的员工平均工资,并且保留平均工资大于10000的部门
select post,avg(salary) from emp
where age > 30 # 1 先筛掉年龄小于30的
group by post # 2 得到30岁以上的员工组成的部门
having avg(salary) > 10000;
"""
1.from
2.where
3.group by
4.having
5.select
"""
#强调:having必须在group by后面使用
select * from emp having avg(salary) > 10000; # 报错
distinct去重
"""
distinct去重
必须是完全一样的数据才能去重
"""
select distinct id,age from emp; # 包含id肯定无法去重
order by排序
# 按照年龄排序
select * from emp order by age; # 默认 升序(从小到大) asc
select * from emp order by age asc; # 升序
select * from emp order by age desc; # 降序
# 单个条件比不出大小 可以比多个
select * from emp order by age,salary; # 第一个字段比不出来就用第二个
select * from emp order by age,salary desc;
# 统计各部门年龄在10岁以上的员工平均工资,并且保留平均工资大于1000的部门,然后对平均工资进行排序
select post,avg(salary) from emp
where age > 10
group by post
having avg(salary) > 1000
order by avg(salary);
limit限制展示条数
select * from emp limit 5; # 只要最开始的五条
select * from emp limit 0,5;
select * from emp limit 5,5;
select * from emp limit 起始位置,展示条数;
正则
我们的sql语句中也支持你书写正则表达式
"""
就是用特殊的符号 来帮你去一大段文本中匹配对应的内容
"""
select * from emp where name regexp '^j.*(n|y)$';
'^j.*(n|y)$':查看以字母j开头 字母n或者y结尾的字符串
多表操作
#建表
create table dep(
id int primary key auto_increment,
name varchar(20)
);
create table emp(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);
#插入数据
insert into dep values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营');
insert into emp(name,sex,age,dep_id) values
('jason','male',18,200),
('egon','female',48,201),
('kevin','male',18,201),
('nick','male',28,202),
('owen','male',18,203),
('jerry','female',18,204);
select * from dep,emp; # 结果是一个笛卡尔积(不需要掌握)
select * from dep,emp where dep.id = emp.dep_id; # 一定要加表前缀
连表操作
"""
inner join
left join
right join
union
"""
# inner join 内连接 只按照两张表都有的数据拼接(没有的就都不拼接)
select * from dep inner join emp on dep.id = emp.dep_id;
# left join 左连接 以左表为基准展示所有的数据(没有对应的用NULL代替)
select * from dep left join emp on dep.id = emp.dep_id;
# right join 右连接 以右表为基准展示所有的数据(没有对应的用NULL代替)
select * from dep right join emp on dep.id = emp.dep_id;
# union
select * from dep left join emp on dep.id = emp.dep_id
union
select * from dep right join emp on dep.id =emp.dep_id