MySQL第四讲

昨日内容回顾

  • 表与表之间建关系(外键)

    """
    表与表之间最多只有四种关系
    	一对多
    	多对多
    	一对一
    	没有关系
    
    在确定表与表之间的关系的时候记住一句话
    	换位思考
    """
    # 一对多(一对多、多对一都叫	一对多)
    """
    一对多关系字段放在多的一方
    以员工表和部门表
    	员工表就是多的一方 所以外键字段应该建在员工表里面
    """
    站在两张表的基础之上 只有一方成立 那么就是一对多
    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

猜你喜欢

转载自www.cnblogs.com/abudrSatan1998/p/13404654.html