一、单表查询
'''数据准备'''
create table student(
id int primary key auto_increment,
name varchar(64) not null,
gender enum('男','女') not null,
height varchar(64),
area varchar(20) default '中国',
port varchar(20) default '未知',
school varchar(20)
);
insert into student(name,gender,height,area,port,school) values('aaa','女','173.1','甘肃','张掖','清华'),
('bbb','男','183.1','上海','青浦','北大'),
('ccc','男','183.3','北京','朝阳','复旦'),
('ddd','男','185.9','广东','广州','清华'),
('eee','女','168','山东','烟台','北大'),
('fff','女','165','新疆','乌鲁木齐','北大'),
('ggg','男','179','河南','洛阳','清华'),
('hhh','女','166.1','广州','广东','复旦'),
('kkk','男','175','上海','浦东','清华'),
('mmm','女','173.1','上海','浦西','复旦'),
('nnn','女','174.8','哈尔滨','齐齐哈尔','清华'),
('ooo','男','176','江苏','南通','复旦'),
('ppp','女','155','江苏','连云港','清华');
+----+------+--------+--------+-----------+--------------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+-----------+--------------+--------+
| 1 | aaa | 女 | 173.1 | 甘肃 | 张掖 | 清华 |
| 2 | bbb | 男 | 183.1 | 上海 | 青浦 | 北大 |
| 3 | ccc | 男 | 183.3 | 北京 | 朝阳 | 复旦 |
| 4 | ddd | 男 | 185.9 | 广东 | 广州 | 清华 |
| 5 | eee | 女 | 168 | 山东 | 烟台 | 北大 |
| 6 | fff | 女 | 165 | 新疆 | 乌鲁木齐 | 北大 |
| 7 | ggg | 男 | 179 | 河南 | 洛阳 | 清华 |
| 8 | hhh | 女 | 166.1 | 广州 | 广东 | 复旦 |
| 9 | kkk | 男 | 175 | 上海 | 浦东 | 清华 |
| 10 | mmm | 女 | 173.1 | 上海 | 浦西 | 复旦 |
| 11 | nnn | 女 | 174.8 | 哈尔滨 | 齐齐哈尔 | 清华 |
| 12 | ooo | 男 | 176 | 江苏 | 南通 | 复旦 |
| 13 | ppp | 女 | 155 | 江苏 | 连云港 | 清华 |
+----+------+--------+--------+-----------+--------------+--------+
1.1增删改查
增
insert [into]
[数据库名.]表名[(字段1[, ..., 字段n])]
values
(数据1[, ..., 数据n])[, ..., (数据1[, ..., 数据n])];
删
delete from [数据库名.]表名 [条件];
改
updata [数据库名.]表名 set 字段1=值1[, ..., 字段n=值n] [条件];
查
select [distinct] 字段1 [[as] 别名1],...,字段n [[as] 别名n] from [数据库名.]表名 [条件];
条件
#层层筛选后的结果:
from、where、group by、having、distinct、order by、limit
***********************所有的条件可以缺失,种类可以不全,但是千万不可以乱序*********************
1.2where条件
比较运算符:= 、 < 、 > 、 <= 、 >= 、 !=
eg: select * from student where school = '清华';
+----+------+--------+--------+-----------+--------------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+-----------+--------------+--------+
| 1 | aaa | 女 | 173.1 | 甘肃 | 张掖 | 清华 |
| 4 | ddd | 男 | 185.9 | 广东 | 广州 | 清华 |
| 7 | ggg | 男 | 179 | 河南 | 洛阳 | 清华 |
| 9 | kkk | 男 | 175 | 上海 | 浦东 | 清华 |
| 11 | nnn | 女 | 174.8 | 哈尔滨 | 齐齐哈尔 | 清华 |
| 13 | ppp | 女 | 155 | 江苏 | 连云港 | 清华 |
+----+------+--------+--------+-----------+--------------+--------+
区间运算符:
- between 1 and 5 :(A~B)
- in(1,3,5) :1或3或5
eg: select * from student where id between 1 and 5; #查询id为1-5的数据 闭合区间
+----+------+--------+--------+--------+--------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------+--------+
| 1 | aaa | 女 | 173.1 | 甘肃 | 张掖 | 清华 |
| 2 | bbb | 男 | 183.1 | 上海 | 青浦 | 北大 |
| 3 | ccc | 男 | 183.3 | 北京 | 朝阳 | 复旦 |
| 4 | ddd | 男 | 185.9 | 广东 | 广州 | 清华 |
| 5 | eee | 女 | 168 | 山东 | 烟台 | 北大 |
+----+------+--------+--------+--------+--------+--------+
eg: select * from student where id in(2, 4, 6, 8); # 分离的区间,2,4,6,8都会被显示
+----+------+--------+--------+--------+--------------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------------+--------+
| 2 | bbb | 男 | 183.1 | 上海 | 青浦 | 北大 |
| 4 | ddd | 男 | 185.9 | 广东 | 广州 | 清华 |
| 6 | fff | 女 | 165 | 新疆 | 乌鲁木齐 | 北大 |
| 8 | hhh | 女 | 166.1 | 广州 | 广东 | 复旦 |
+----+------+--------+--------+--------+--------------+--------+
逻辑运算符:and、or、not
eg: select * from student where area="山东" and port="烟台";
+----+------+--------+--------+--------+--------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------+--------+
| 5 | eee | 女 | 168 | 山东 | 烟台 | 北大 |
+----+------+--------+--------+--------+--------+--------+
相似运算符
like '_a%': _表示一个字符(a前面一个字符),%表示任意字符(a后面任意多个字符)
eg: select * from student where name like '__a';
+----+------+--------+--------+--------+--------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------+--------+
| 1 | aaa | 女 | 173.1 | 甘肃 | 张掖 | 清华 |
+----+------+--------+--------+--------+--------+--------+
eg: select * from student where name like 'k%';
+----+------+--------+--------+--------+--------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------+--------+
| 9 | kkk | 男 | 175 | 上海 | 浦东 | 清华 |
+----+------+--------+--------+--------+--------+--------+
eg: select * from student where name like '_m%';
+----+------+--------+--------+--------+--------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------+--------+
| 10 | mmm | 女 | 173.1 | 上海 | 浦西 | 复旦 |
+----+------+--------+--------+--------+--------+--------+
正则匹配:regexp
'''基于字符串查数据'''
# sql只支持部分正则语法
eg: select * from student where name regexp '.*d'; # 不支持d代表数字,认为d就是普通字符串
eg: select * from student where name regexp '.*[f-k]'; #支持[]语法,[]里面可以写a-z,A-Z,0-9
+----+------+--------+--------+--------+--------------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------------+--------+
| 6 | fff | 女 | 165 | 新疆 | 乌鲁木齐 | 北大 |
| 7 | ggg | 男 | 179 | 河南 | 洛阳 | 清华 |
| 8 | hhh | 女 | 166.1 | 广州 | 广东 | 复旦 |
| 9 | kkk | 男 | 175 | 上海 | 浦东 | 清华 |
+----+------+--------+--------+--------+--------------+--------+
1.3分组与筛选:group by | having
where与having
'''在没有分组的情况下,where与having查询的结果相同'''
'''having可以对 聚合结果 进行筛选'''
eg: select * from student where height > 180;
+----+------+--------+--------+--------+--------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------+--------+
| 2 | bbb | 男 | 183.1 | 上海 | 青浦 | 北大 |
| 3 | ccc | 男 | 183.3 | 北京 | 朝阳 | 复旦 |
| 4 | ddd | 男 | 185.9 | 广东 | 广州 | 清华 |
+----+------+--------+--------+--------+--------+--------+
eg: select * from student having height > 180;
+----+------+--------+--------+--------+--------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------+--------+
| 2 | bbb | 男 | 183.1 | 上海 | 青浦 | 北大 |
| 3 | ccc | 男 | 183.3 | 北京 | 朝阳 | 复旦 |
| 4 | ddd | 男 | 185.9 | 广东 | 广州 | 清华 |
+----+------+--------+--------+--------+--------+--------+
聚合函数
"""
max():最大值
min():最小值
avg():平均值
sum():和
count():记数
group_concat():组内字段拼接,用来查看组内其他字段
"""
eg:略
分组查询:group by
eg: select * from student group by school;
+----+------+--------+--------+--------+--------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+--------+--------+--------+
| 2 | bbb | 男 | 183.1 | 上海 | 青浦 | 北大 |
| 3 | ccc | 男 | 183.3 | 北京 | 朝阳 | 复旦 |
| 1 | aaa | 女 | 173.1 | 甘肃 | 张掖 | 清华 |
+----+------+--------+--------+--------+--------+--------+
#这样的分组查询是错误的,因为他只显示了每个组的第一个人
#所以我们要对他进行一些数据库配置操作, 有ONLY_FULL_GROUP_BY之后,让数据库看见如此的语法,直接报错
'''
修改my.ini配置重启mysql服务
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
'''
'''分组'''
假如将 学校进行分组,分别分为了清华、北大、复旦 这就是分组
eg: 按学校分组,每个学校都有哪些人、姓名、性别、身高、组里一共有多少人
'''聚合'''
就是把多条数据统一处理
每个学校都有哪些人、姓名、性别、身高、组里一共有多少人就是聚合的结果
'''参与分组的字段,也归于 聚合结果'''
也就是分为几个学校这个也算聚合的结果
eg:
select
school,
group_concat(name) 学生,
max(height) 最高身高,
min(height) 最低身高,
avg(height) 平均身高,
count(gender) 人数
from student group by school;
+--------+-------------------------+--------------+--------------+--------------------+--------+
| school | 学生 | 最高身高 | 最低身高 | 平均身高 | 人数 |
+--------+-------------------------+--------------+--------------+--------------------+--------+
| 北大 | bbb,eee,fff | 183.1 | 165 | 172.03333333333333 | 3 |
| 复旦 | ccc,ooo,hhh,mmm | 183.3 | 166.1 | 174.625 | 4 |
| 清华 | aaa,nnn,kkk,ggg,ddd,ppp | 185.9 | 155 | 173.79999999999998 | 6 |
+--------+-------------------------+--------------+--------------+--------------------+--------+
eg:
select
school,
max(height) 最高身高
from student group by school;
+--------+--------------+
| school | 最高身高 |
+--------+--------------+
| 北大 | 183.1 |
| 复旦 | 183.3 |
| 清华 | 185.9 |
+--------+--------------+
分组后的having
'''having可以对 聚合结果 再进行筛选,where不可以'''
eg:
select
school,
group_concat(name) 学生,
max(height) 最高身高,
min(height) 最低身高,
avg(height) 平均身高,
count(gender) 人数
from student group by school having avg(height)<173;
# having 再一次筛选了avg(height)<173的信息,所以就剩下一条数据了
+--------+-------------+--------------+--------------+--------------------+--------+
| school | 学生 | 最高身高 | 最低身高 | 平均身高 | 人数 |
+--------+-------------+--------------+--------------+--------------------+--------+
| 北大 | bbb,eee,fff | 183.1 | 165 | 172.03333333333333 | 3 |
+--------+-------------+--------------+--------------+--------------------+--------+
1.4 排序
#asc:升序(不写默认升序)
#desc:降序
order by
主排序字段 [asc|desc],
次排序字段1 [asc|desc],
...次排序字段n [asc|desc]
未分组状态
eg:
# 按身高升序
select * from student order by height;
+----+------+--------+--------+-----------+--------------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+-----------+--------------+--------+
| 13 | ppp | 女 | 155 | 江苏 | 连云港 | 清华 |
| 6 | fff | 女 | 165 | 新疆 | 乌鲁木齐 | 北大 |
| 8 | hhh | 女 | 166.1 | 广州 | 广东 | 复旦 |
| 5 | eee | 女 | 168 | 山东 | 烟台 | 北大 |
| 10 | mmm | 女 | 173.1 | 上海 | 浦西 | 复旦 |
| 1 | aaa | 女 | 173.1 | 甘肃 | 张掖 | 清华 |
| 11 | nnn | 女 | 174.8 | 哈尔滨 | 齐齐哈尔 | 清华 |
| 9 | kkk | 男 | 175 | 上海 | 浦东 | 清华 |
| 12 | ooo | 男 | 176 | 江苏 | 南通 | 复旦 |
| 7 | ggg | 男 | 179 | 河南 | 洛阳 | 清华 |
| 2 | bbb | 男 | 183.1 | 上海 | 青浦 | 北大 |
| 3 | ccc | 男 | 183.3 | 北京 | 朝阳 | 复旦 |
| 4 | ddd | 男 | 185.9 | 广东 | 广州 | 清华 |
+----+------+--------+--------+-----------+--------------+--------+
# 按id降序
select * from student order by id desc;
+----+------+--------+--------+-----------+--------------+--------+
| id | name | gender | height | area | port | school |
+----+------+--------+--------+-----------+--------------+--------+
| 13 | ppp | 女 | 155 | 江苏 | 连云港 | 清华 |
| 12 | ooo | 男 | 176 | 江苏 | 南通 | 复旦 |
| 11 | nnn | 女 | 174.8 | 哈尔滨 | 齐齐哈尔 | 清华 |
| 10 | mmm | 女 | 173.1 | 上海 | 浦西 | 复旦 |
| 9 | kkk | 男 | 175 | 上海 | 浦东 | 清华 |
| 8 | hhh | 女 | 166.1 | 广州 | 广东 | 复旦 |
| 7 | ggg | 男 | 179 | 河南 | 洛阳 | 清华 |
| 6 | fff | 女 | 165 | 新疆 | 乌鲁木齐 | 北大 |
| 5 | eee | 女 | 168 | 山东 | 烟台 | 北大 |
| 4 | ddd | 男 | 185.9 | 广东 | 广州 | 清华 |
| 3 | ccc | 男 | 183.3 | 北京 | 朝阳 | 复旦 |
| 2 | bbb | 男 | 183.1 | 上海 | 青浦 | 北大 |
| 1 | aaa | 女 | 173.1 | 甘肃 | 张掖 | 清华 |
+----+------+--------+--------+-----------+--------------+--------+
eg:
# 按身高降序,如果相同,再按id降序
mysql>: select * from student order by height desc, id desc;
表:略
分组状态
select
school,
group_concat(name) 学生,
max(height) 最高身高,
min(height) 最低身高,
avg(height) 平均身高,
count(gender) 人数
from student group by school order by max(height) desc;
#先分组之后,对最大身高降序
+--------+-------------------------+--------------+--------------+--------------------+--------+
| school | 学生 | 最高身高 | 最低身高 | 平均身高 | 人数 |
+--------+-------------------------+--------------+--------------+--------------------+--------+
| 清华 | aaa,nnn,kkk,ggg,ddd,ppp | 185.9 | 155 | 173.79999999999998 | 6 |
| 复旦 | ccc,ooo,hhh,mmm | 183.3 | 166.1 | 174.625 | 4 |
| 北大 | bbb,eee,fff | 183.1 | 165 | 172.03333333333333 | 3 |
+--------+-------------------------+--------------+--------------+--------------------+--------+
1.5 limit(限制)
limit 条数
eg:
select id,name,gender,height,school
from student where height<175
order by id desc limit 3;
#只显示前3条数据
+----+------+--------+--------+--------+
| id | name | gender | height | school |
+----+------+--------+--------+--------+
| 13 | ppp | 女 | 155 | 清华 |
| 11 | nnn | 女 | 174.8 | 清华 |
| 10 | mmm | 女 | 173.1 | 复旦 |
+----+------+--------+--------+--------+
limit 偏移量,条数
eg:
select id,name,gender,height,school
from student where height<175
order by id desc limit 2,3;
#先偏移2条满足条件的记录,再查询3条
+----+------+--------+--------+--------+
| id | name | gender | height | school |
+----+------+--------+--------+--------+
| 10 | mmm | 女 | 173.1 | 复旦 |
| 8 | hhh | 女 | 166.1 | 复旦 |
| 6 | fff | 女 | 165 | 北大 |
+----+------+--------+--------+--------+
1.6 常用函数
"""
拼接:concat() | concat_ws()
大小写:upper() | lower()
浮点型操作:ceil() | floor() | round()
整型:可以直接运算
"""
eg: select name,area,port from student;
eg: select name as 姓名, concat(area,'-',port) 地址 from student; # 甘肃-张掖
eg: select name as 姓名, concat_ws('-',area,port,school) 信息 from student; # 甘肃-张掖-清华
mysql>: select upper(name) 姓名大写,lower(name) 姓名小写 from student;
+--------------+--------------+
| 姓名大写 | 姓名小写 |
+--------------+--------------+
| AAA | aaa |
...
eg: select id,name,height,
ceil(height)上身高,
floor(height)下身高,
round(height)四舍五入身高
from student;
+----+------+--------+-----------+-----------+--------------------+
| id | name | height | 上身高 | 下身高 | 四舍五入身高 |
+----+------+--------+-----------+-----------+--------------------+
| 1 | aaa | 173.1 | 174 | 173 | 173 |
| 2 | bbb | 183.1 | 184 | 183 | 183 |
...
mysql>: select name 姓名, height 旧身高, height+1 新身高 from student;
+--------+-----------+-----------+
| 姓名 | 旧身高 | 新身高 |
+--------+-----------+-----------+
| aaa | 173.1 | 174.1 |
...
1.7 distinct
mysql>:
create table t1(
id int,
x int,
y int
);
mysql>: insert into t1 values(1, 1, 1), (2, 1, 2), (3, 2, 2), (4, 2, 2);
mysql>: select distinct * from t1; # 全部数据
mysql>: select distinct x, y from t1; # 结果 1,1 1,2 2,2
mysql>: select distinct y from t1; # 结果 1 2
# 总结:distinct对参与查询的所有字段,整体去重(所查的全部字段的值都相同,才认为是重复数据)
二、多表查询
连接
# 连接:将有联系的多张表通过关联(有联系就行,不一定是外键)字段,进行连接,形成一张大表
# 连表查询:在大表的基础上进行查询,就称之为连表查询
# 将表与表建立连接的方式有四种:内连接、左连接、右连接、全连接
一对多数据准备
mysql>: create database db3;
mysql>: use db3;
mysql>:
create table dep(
id int primary key auto_increment,
name varchar(16),
work varchar(16)
);
create table emp(
id int primary key auto_increment,
name varchar(16),
salary float,
dep_id int
);
insert into dep values(1, '市场部', '销售'), (2, '教学部', '授课'), (3, '管理部', '开车');
insert into emp(name, salary, dep_id) values('egon', 3.0, 2),('yanghuhu', 2.0, 2),('sanjiang', 10.0, 1),('owen', 88888.0, 2),('liujie', 8.0, 1),('yingjie', 1.2, 0);
笛卡尔积
# 笛卡尔积: 集合 X{a, b} * Y{o, p, q} => Z{{a, o}, {a, p}, {a, q}, {b, o}, {b, p}, {b, q}}
mysql>: select * from emp, dep;
# 总结:是两张表 记录的所有排列组合,数据没有利用价值
内连接
# 关键字:inner join on
# 语法:from A表 inner join B表 on A表.关联字段=B表.关联字段
mysql>:
select
emp.id,emp.name,salary,dep.name,work
from emp inner join dep on emp.dep_id = dep.id
order by emp.id;
# 总结:只保留两个表有关联的数据
左连接
# 关键字:left join on
# 语法:from 左表 left join 右表 on 左表.关联字段=右表.关联字段
mysql>:
select
emp.id,emp.name,salary,dep.name,work
from emp left join dep on emp.dep_id = dep.id
order by emp.id;
# 总结:保留左表的全部数据,右表有对应数据直接连表显示,没有对应关系空填充
右连接
# 关键字:right join on
# 语法:from A表 right join B表 on A表.关联字段=B表关联字段
mysql>:
select
emp.id,emp.name,salary,dep.name,work
from emp right join dep on emp.dep_id = dep.id
order by emp.id;
# 总结:保留右表的全部数据,左表有对应数据直接连表显示,没有对应关系空填充
左右可以相互转化
mysql>:
select
emp.id,emp.name,salary,dep.name,work
from emp right join dep on emp.dep_id = dep.id
order by emp.id;
mysql>:
select
emp.id,emp.name,salary,dep.name,work
from dep left join emp on emp.dep_id = dep.id
order by emp.id;
# 总结:更换一下左右表的位置,相对应更换左右连接关键字,结果相同
全连接
mysql>:
select
emp.id,emp.name,salary,dep.name,work
from emp left join dep on emp.dep_id = dep.id
union
select
emp.id,emp.name,salary,dep.name,work
from emp right join dep on emp.dep_id = dep.id
order by id;
# 总结:左表右表数据都被保留,彼此有对应关系正常显示,彼此没有对应关系均空填充对方
一对一与一对多情况一致
# 创建一对一 作者与作者详情 表
create table author(
id int,
name varchar(64),
detail_id int
);
create table author_detail(
id int,
phone varchar(11)
);
# 填充数据
insert into author values(1, 'Bob', 1), (2, 'Tom', 2), (3, 'ruakei', 0);
insert into author_detail values(1, '13344556677'), (2, '14466779988'), (3, '12344332255');
# 内连
select author.id,name,phone from author join author_detail on author.detail_id = author_detail.id order by author.id;
# 全连
select author.id,name,phone from author left join author_detail on author.detail_id = author_detail.id
union
select author.id,name,phone from author right join author_detail on author.detail_id = author_detail.id
order by id;
多对多:两表两表建立连接
# 在一对一基础上,建立 作者与书 的多对多关系关系
# 利用之前的作者表
create table author(
id int,
name varchar(64),
detail_id int
);
insert into author values(1, 'Bob', 1), (2, 'Tom', 2), (3, 'ruakei', 0);
# 创建新的书表
create table book(
id int,
name varchar(64),
price decimal(5,2)
);
insert into book values(1, 'python', 3.66), (2, 'Linux', 2.66), (3, 'Go', 4.66);
# 创建 作者与书 的关系表
create table author_book(
id int,
author_id int,
book_id int
);
# 数据:author-book:1-1,2 2-2,3 3-1,3
insert into author_book values(1,1,1),(2,1,2),(3,2,2),(4,2,3),(5,3,1),(6,3,3);
# 将有关联的表一一建立连接,查询所以自己所需字段
select book.name, book.price, author.name, author_detail.phone from book
join author_book on book.id = author_book.book_id
join author on author_book.author_id = author.id
left join author_detail on author.detail_id = author_detail.id;