MySQL表单的查询及分组聚合整理

单表查询

1.表与表关系

1.1校区表 班级表 一对多

​ 校区表 一个校区可以有多个班级 一对多
​ 班级表 一个班级可不可以对应多个校区
​ 校区表 校区id 校区名称 校区城市 校区地址
​ 班级表 班级id 班级名称 开班日期 班主任 校区id
​ 多(foreign key)关联一这张表
​ 班级表创建foreign key关联校区表的校区id字段

1.2学生表 班级表 多对多

​ 站在学生的角度上 一个学生属于多个班级 一对多
​ 站在班级的角度上 一个班级可以有多个学生么 多对一
​ 学生表 学生id 学生姓名 ...
​ 班级表 班级id 班级名称 ...
​ 产生第三张表
​ 一个字段是外键关联另一个表的主键
​ 另一个字段外键关联另一张表的主键

1.3学生表 客户表 一对一

​ 一个客户对应一个学生
​ 学生表gid foreign key 关联客户表id主键
​ 并且gid还要设置为unique

2.单表查询

2.1有关查看的语句

select user(); # 查看当前用户
select database(); # 查看当前数据库
select now(); # 查看当前时间

2.2查看的基本语法

# select *(全部) from 表名;
select * from t1;
# select 字段名 from 表名;
select name from t1:
# select 字段名,字段名,字段名 from 表名;
select name, age from t1;

2.3distinct(去重)

# select distinct 字段 from 表;
select distinct name from t1;
# 对查出来的字段进行去重

2.4查询能进行四则运算

# select emp_name,salary*12 from 表
select emp_name,salary*12 from t1
# 字段salary参与了四则运算

2.5concat

对字段进行加工

# select concat(字段,'字符串1',字段) from 表
select concat(emp_name,' : ',salary) from employee;
# 如果按照上面的写法,加工后的字段名就会变为concat(emp_name,' : ',salary),很难看

select concat(emp_name,' : ',salary) as info from employee;
select concat(emp_name,' : ',salary) info from employee;
# 上面的两种写法效果相同,将字段名变为info

# 加工后的效果为------>姓名:工资

2.6concat_ws

# select concat_ws('分隔符',字符串,字段1,字段2) info from employee;
select concat_ws('|','信息',emp_name,salary) info from employee;
# 使用分隔符将信息分隔开,可以加入字符串进行辅助拼接
# 与concat类似可以修改字段名

2.7case

select(
    case # 语句头,相当于begin
    when emp_name = 'alex' then # when 条件 then
        concat(emp_name,'BIGSB') # 输出查询的字段,可加工
    when emp_name = 'jingliyang' then
        emp_name
    else					# 最后一条写else
        concat(emp_name,'sb')
    end # 语句尾
    ) as new_name # 字段重命名
from employee;

2.8where筛选行

select * from 表 where 条件

2.8.1范围查询

①>大于

select age from t1 where age > 20;

②<小于

select age from t1 where age < 20;

③>=大于等于

select age from t1 where age >= 20;

④<=小于

select age from t1 where age <= 20;

⑤=等于

select age from t1 where age = 20;

⑥!=或<>不等于

select age from t1 where age != 20;
# 或
select age from t1 where age <> 20;

2.8.2模糊查询

①like:

Ⅰ. % 一个百分号代表任意长度的任意字符

# 'a%' 判断以a开头
select name from t1 where name like 'a%';
# '%ing' 判断以ing结尾
select name from t1 where name like '%ing';
# '%a%' 判断存在a
select name from t1 where name like '%a%';

Ⅱ. _ 一个下划线代表一个任意字符

# 'a__' 判断以a开头的三个字符
select name from t1 where name like 'a__';

②regexp

实际上就是进行正则运算

# '^a' 判断以a开头
select name from t1 where name regexp '^a';
# 'a$'判断以a结尾
select name from t1 where name regexp 'a$';

2.8.3 is与is not

# 数据库中不能使用=去判断null,因此提供了is与is not 去判断null
select name from t1 where name is null;
select name from t1 where name is not null;

2.8.4逻辑运算

# and
select name from t1 where name='alex' and age = 18;
# or
select name from t1 where name='alex' or name = 'sb';
# not
select name from t1 where not age > 30;

3.表的修改

# alter table 表名 rename 新表名;
alter table t1 rename t2;
# alter table 表名 add 新字段 类型(宽度) 约束;
alter table t2 add post char(12) not null;
# add 新字段 类型(宽度) 约束 after id
alter table t2 add post char(12) not null after id; # 插在id之后
# add 新字段 类型(宽度) 约束 first
alter table t2 add post char(12) not null first; # 排头
# alter table 表名 drop 字段名;
alter table t1 drop post;
# alter table 表名 change 旧字段 新字段 类型(宽度) 约束;
alter table t1 change name new_name char(20) not null;
alter table t1 change name name char(12) null;# 使name可以为空
# alter table 表名 modify 存在的字段 新类型(新宽度) 新约束;
alter table t1 modify name char(12) unique;
alter table t1 modify name char(12) unique after id;

4.数据操作补充

# 增加
# insert into 表名 value (1,'alex','female') 使用value一次只能增加一条记录
insert into t1 value (1, 'alex', 'female');
# insert into 表名 values (1,'alex','female'),(1,'alex','female');
insert into t1 values (1, 'alex', 'female'),(2, 'alex', 'female')
# insert into 表名(name,gender) values ('alex','female');    *****常用
insert into t1(name, gender) values ('alex', 'female'),('alexsb', 'female');
# insert into 表名(name,gender) select (username,sex) from 表2;
insert into t1(name, gender) select (username, sex) from t2;


# 修改
# update 表名 set 字段=值1 where 条件
update t1 set age=18 where age > 18;
# update 表名 set 字段1=值1,字段2=值2 where 条件
update t1 set age=18, sex='女' where age > 18 and sex='男';

数据库中的分组与聚合

1.数据库中关键字的执行顺序

①select 想要的列 from 表
②where 先从这张表中查询的行
③group by 分组
④having 对组过滤
⑤order by 排序
⑥limit 取一个区间

2.分组(group by)

使用情况:

根据某个重复率比较高的字段进行的,
这个字段有多少种可能就分成多少个组

功能:

①分组
②去重
注:一旦分组了就不能对具体某一条数据进行操作了

数据表:

# 使用group by
select * from employee group by post;

使用group by 时会出现一些问题:

这里引出group_concat()

select group_concat(emp_name) from employee where post='teacher' group by post;

3.聚合(count,max,min,sum,avg)

聚合:

99.99%的情况都是和分组一起用的
如果没有和分组一起用,默认一整张表是一组

# count(id)  / count(*) 计数 :每个组对应几条数据
select count(id) from employee;
# max 求最大值: 这个组中某字段的最大值
select max(hire_date) from employee;
# min 求最大值: 这个组中某字段的最小值
select min(hire_date) from employee;
# avg 求平均值
select avg(salary) from employee;
# sum 求和值
select sum(salary) from employee;

4.过滤(having)

# 就是一个对组进行筛选的条件
# 要部门人数大于3个人的部门 count(id)>3
select post from employee group by post having count(id)>3;

5.排序(order by)

# order by 字段(升序)
select emp_name,age from employee order by age;
# order by 字段 asc(升序)
select emp_name,age from employee order by age asc;
# order by 字段 desc(降序)
select emp_name,age from employee order by age desc;

# order by 字段1,字段2(对字段1升序,然后在字段1的基础下对字段2升序)
select emp_name,age from employee order by age,salary;
# order by 字段 asc,字段2 desc(对字段1升序,然后在字段1的基础下对字段2降序)
select emp_name,age from employee order by age asc,salary desc;
# order by 字段 desc,字段2 asc(对字段1降序,然后在字段1的基础下对字段2升序)
select emp_name,age from employee order by age desc,salary asc;
# order by 字段 desc,字段2 desc(对字段1降序,然后在字段1的基础下对字段2降序)
select emp_name,age from employee order by age desc,salary desc;

6.限制(limit)

limit的用途:

①显示分页

# limit m,n
    # 若写为limit n,默认m为0
    # 表示从m+1开始,取n条
    # limit 0,6 表示从1开始取6条
    # limit 6,6 表示从7开始取6条
    # limit 12,6 表示从13开始取6条
    # limit 18,6 表示从19开始取6条
    
# 只显示一条信息
select emp_name,age from employee limit 1;
select emp_name,age from employee limit 0,1;# (两条效果相同)

################################################################
# 有时面试中面试官会问 limit offset的用法,你会懵逼!
# limit n offset m :从m+1开始,取n条 (*******************************)
limit 1 offset 0; 与 limit 0,1; limit 1; 完全一样!!!!!

②取前n名

# 跟order by一起用
# 取最小年龄
select emp_name,age from employee order by age limit 1;

7.使用python操作数据库

注:你的python中有pymysql模块

import pymysql
conn = pymysql.Connection(host='127.0.0.1', user='root', password="123",database='db1') # 相当于socket里面的conn
cur = conn.cursor() # 记住

lst = ['学python从开始到放弃|alex|人民大学出版社|50|2018-7-1',
'学mysql从开始到放弃|egon|机械工业出版社|60|2018-6-3',
'学html从开始到放弃|alex|机械工业出版社|20|2018-4-1',
'学css从开始到放弃|wusir|机械工业出版社|120|2018-5-2',
'学js从开始到放弃|wusir|机械工业出版社|100|2018-7-30']

sql = 'insert into book values(%s,%s,%s,%s,%s)' # 格式化
for i in lst:
    cur.execute(sql, (i.split('|'))) # 后面传参要用可迭代对象
    
conn.commit() # 将数据提交至数据库写入
cur.close() # 关闭
conn.close() # 关闭

多表查询

1.连表查询前的序曲

1.1数据准备

#建表
create table department(
id int,
name varchar(20) 
);

create table employee(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);

#插入数据
insert into department values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营');

insert into employee(name,sex,age,dep_id) values
('egon','male',18,200),
('alex','female',48,201),
('wupeiqi','male',38,201),
('yuanhao','female',28,202),
('liwenzhou','male',18,200),
('jingliyang','female',18,204)
;

1.2笛卡尔积

先计算两张表的笛卡尔积,再根据用户给出的条件进行筛选

# 连表
select * from employee,department;

因此我们可以使用where来进行筛选:

select * from employee,department where dep_id = department.id;

但是这里也会存在问题,我们这里通过where来进行连表操作,导致where字段被占用了,无法对后续的记录进行筛选.因此这个连表操作是错误的!

2.连表操作

概念:原来是两张表,现在拼成一张表,所有的操作都像是操作一张表一样了

2.1内连接

# 内连接  inner join ... on 连接条件
# select * from 表1 inner join 表2 on 条件
select * from employee inner join department on dep_id = department.id;
       # employee --> dep_id: 200,201,202,204
       # department --> id : 200,201,202,203
# 内连接 :只显示两张表中互相匹配的项,其他不匹配的不显示

2.2外链接

2.2.1左外连接

# 左外连接 left join .. on
# select * from 表1 left join 表2 on 条件
select * from employee left join department on dep_id = department.id;
# 不管左表中是不是匹配上都会显示所有内容
select * from department left join employee  on dep_id = department.id;
# 不管左表中是不是匹配上都会显示所有内容

2.2.2右外链接

# 右外连接 right join .. on
# select * from 表1 right join 表2 on 条件
select * from employee right join department on dep_id = department.id;
# 不管右表中是不是匹配上都会显示所有内容

2.2.3全外链接

mysql不支持full join 的写法,但是可通过union来实现全外连接

select * from department left join employee  on dep_id = department.id
union
select * from department right join employee on dep_id = department.id;

3.子查询

3.1概念

1:子查询是将一个查询语句嵌套在另一个查询语句中。
2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
4:还可以包含比较运算符:= 、 !=、> 、<等

3.2实例

in:

# 存在年龄大于25岁员工的部门
select distinct dep_id from employee where age>25;
# 查询年龄大于25的员工的部门id并去重
select * from department where id in (select distinct dep_id from employee where age>25);
# 使用in 去筛选

exists:

select * from employee
where exists
(select id from department where id=200);
# 使用EXISTS关键字时,内层查询语句不返回查询的记录,而是返回一个真假值,True或False
# 当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询.

4.连表查询与子查询

问题a:

# a.查询平均年龄在25岁以上的部门名
# 第一步:求部门的平均年龄>25岁的 部门id
select dep_id from employee group by dep_id having avg(age)>25;
# 第二步:构建子查询根据部门id求部门名
select name from department where id in (select dep_id from employee group by dep_id having avg(age)>25);

问题b:

# b.查询平均年龄在25岁以上的部门名,平均年龄的值
# 方法1:
# 第一步:先查部门的平均年龄>25岁的部门id,平均年龄
select dep_id,avg(age) from employee group by dep_id having avg(age) > 25;
# 第二步:查出结果在之后再连表
select name,avg_age from department as d right join (select dep_id,avg(age) as avg_age from employee group by dep_id having avg(age) > 25) as t on d.id = t.dep_id;

总结:

①如果最终需要的结果只出现在一张表中,可以用子查询解决问题
②如果最终需要的结果出现在两个表中,那么最后用的一定是连表查询

5.补充select的用法

select还能这么使用:

数据准备:

create table employee(
id int not null unique auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) 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 employee(name,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部
('alex','male',78,'20150302','teacher',1000000.31,401,1),
('wupeiqi','male',81,'20130305','teacher',8300,401,1),
('yuanhao','male',73,'20140701','teacher',3500,401,1),
('liwenzhou','male',28,'20121101','teacher',2100,401,1),
('jingliyang','female',18,'20110211','teacher',9000,401,1),
('jinxin','male',18,'19000301','teacher',30000,401,1),
('成龙','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)
;

实例:

# 求每个部门最早入职的员工姓名
select (select t2.name from employee as t2 where t2.post=t1.post order by hire_date desc limit 1) from employee as t1 group by post;

猜你喜欢

转载自www.cnblogs.com/zheng0907/p/12743101.html