mysql之单表查询、多表查询

mysql查询

单表查询

"""
增:
insert [into]
    [数据库名.]表名[(字段1[,...,字段n])]
values
    (数据1[,...,数据n])[,...,(数据1[,...,数据n])];

eg: 

增:
insert into db1.student(id, name, age) values(1, 'nick', 18);

删:
delete from db1.student where id = 1;

改:
update db1.student set name = 'tank' where id = 1;

"""

#条件:from, where, group by, having, distinct, order by, limit
#==> 层层筛选后的结果

#注:一条查询语句,可以拥有多种筛选条件,条件的顺序必须按照上方的顺序进行逐步筛选,distinct稍有特殊(书写位置),条件的种类可以不全

#可以缺失,但不能乱序

去重:distinct

create table t1(

    id int,
    x int,
    y int
);

insert into t1 values(1, 1, 1), (2, 1, 2), (3, 2, 2), (4, 2, 2);

select distinct * from t1;  
#id为3和4的两列不会去重,按*取值就是这样,即全部数据

select distinct x, y from t1;  
#id为3和4的两列重复了,所以会去掉一组,结果是1,1  1,2  2,2

select distinct y from t1; 
#只筛选y这列,y中的2重复了,结果是1 2

数据准备

CREATE TABLE `emp`  ( 
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL,
  `gender` enum('男','女','未知') NULL DEFAULT '未知',
  `age` int(0) NULL DEFAULT 0,
  `salary` float NULL DEFAULT 0,
  `area` varchar(20) NULL DEFAULT '中国',
  `port` varchar(20) DEFAULT '未知',
  `dep` varchar(20),
  PRIMARY KEY (`id`)
);

INSERT INTO `emp` VALUES 
    (1, 'yangsir', '男', 42, 10.5, '上海', '浦东', '市场部'),
    (2, 'engon', '男', 38, 9.4, '山东', '济南', '研发部'),
    (3, 'jerry', '女', 30, 3.0, '江苏', '张家港', '研发部'),
    (4, 'tank', '女', 28, 2.4, '广州', '广东', '研发部'),
    (5, 'jiboy', '男', 28, 2.4, '江苏', '苏州', '研发部'),
    (6, 'zero', '男', 18, 8.8, '中国', '黄浦', '销售部'),
    (7, 'owen', '男', 18, 8.8, '安徽', '宣城', '研发部'),
    (8, 'jason', '男', 28, 9.8, '安徽', '巢湖', '研发部'),
    (9, 'ying', '女', 36, 1.2, '安徽', '芜湖', '销售部'),
    (10, 'kevin', '男', 36, 5.8, '山东', '济南', '研发部'),
    (11, 'monkey', '女', 28, 1.2, '山东', '青岛', '市场部'),
    (12, 'san', '男', 30, 9.0, '上海', '浦东', '销售部'),
    (13, 'san1', '男', 30, 6.0, '上海', '浦东', '销售部'),
    (14, 'san2', '男', 30, 6.0, '上海', '浦西', '研发部'),
    (15, 'ruakei', '女', 67, 2.501, '上海', '陆家嘴', '研发部');

常用函数

"""
拼接:concat() | concat_ws()
大小写:upper() | lower()
浮点型操作:ceil() | floor() | round()
整型:可以直接运算
"""
select name,area,port from emp;
select concat(name,':',area,'-',port) 个人信息 from emp;
#一张表一列,标题是‘个人信息’,内容是‘yangsir:上海-浦东,....,ruakei: 上海-陆家嘴'

select upper(name) 姓名大写,lower(name) 姓名小写 from emp;
#两列,左侧标题是’姓名大写‘列是大写,右侧标题是’姓名小写‘列是小写。

select id,salary,ceil(salary)上薪资,floor(salary)下薪资,round(salary)入薪资 from emp;
#这里的四舍五入会出现错误,比如round(10.5)得到结果是10,但是round(10.501)得到的结果就是11

select id,salary 旧薪资,salary+1 新薪资 from emp;
#新工资这一列会保留很多小数

条件:where

#多条件协调操作导入: where 奇数 [group by 部门 having 平均薪资] order by [平均]薪资 limit 1

mysql>: select * from emp where id<5 limit 1;  # 正常
mysql>: select * from emp limit 1 where id<5;  # 异常,条件乱序
    
     
# 判断规则
"""
比较符和:>  |  <  |  >=  |  <=  |  =  |  !=
区间符和:between 开始 and 结束 |  in(自定义容器)
逻辑符和:and  |  or  |  not
相似符和:like _|%
正则符和:regexp 正则语法
"""
mysql>: select * from emp where salary>5; #工资大于5的
mysql>: select * from emp where id%2=0; #偶数id的

mysql>: select * from emp where salary between 6 and 9; #工资在6和9之间(包括 6和9 )

mysql>: select * from emp where id in(1, 3, 7, 20); #id包含括号里面要求的

# _o 某o | __o 某某o | _o% 某o* (*是0~n个任意字符) | %o% *o*
mysql>: select * from emp where name like '%o%';
mysql>: select * from emp where name like '_o%';  
mysql>: select * from emp where name like '___o%';

# sql只支持部分正则语法
mysql>: select * from emp where name regexp '.*\d';  # 不支持\d代表数字,认为\d就是普通字符串
mysql>: select * from emp where name regexp '.*[0-9]';  # 支持[]语法
    
mysql>:select * from emp where not name(或者是name not) regexp '.*[0-9]' 
#上面这句话查找的是名字最后一个不是数字的所有名字

分组与筛选:group by | having

where与having
# 表象:在没有分组的情况下,where与having结果相同
# 重点:having可以对 聚和结果 进行筛选
mysql>: select * from emp where salary > 5;
mysql>: select * from emp having salary > 5;

mysql>: select * from emp where id in (5, 10, 15, 20);
mysql>: select * from emp having id in (5, 10, 15, 20);
聚合函数
"""
max():最大值
min():最小值
avg():平均值
sum():和
count():记数
group_concat():组内字段拼接,用来查看组内其他字段
"""
分组查询 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

# 在sql_mode没有 ONLY_FULL_GROUP_BY 限制下,可以执行,但结果没有意义
# 有 ONLY_FULL_GROUP_BY 限制,报错
mysql>: select * from emp group by dep;

# 分组后,表中数据考虑范围就不是 单条记录,因为每个分组都包含了多条记录,参照分组字段,对每个分组中的 多条记录 统一处理
# eg: 按部门分组,每个部门都有哪些人、最高的薪资、最低的薪资、平均薪资、组里一共有多少人

# 将多条数据统一处理,这种方式就叫 聚和
# 每个部门都有哪些人、最高的薪资、最低的薪资、平均薪资 都称之为 聚和结果 - 聚和函数操作的结果
# 注:参与分组的字段,也归于 聚和结果

mysql>: 
select 
    dep 部门,
    group_concat(name) 成员,
    max(salary) 最高薪资,
    min(salary) 最低薪资,
    avg(salary) 平均薪资,
    sum(salary) 总薪资,
    count(gender) 人数
from emp group by dep;

# 先从emp里面按照dep进行分组,然后把列出的字段表示出来。

# 总结:分组后,查询条件只能为 分组字段(即按照dep分组后的字段) 和 聚和函数(即select中选择的函数)操作的聚和结果
分组后的having
mysql>: 
select 
    dep 部门,
    group_concat(name) 成员,
    max(salary) 最高薪资,
    min(salary) 最低薪资,
    avg(salary) 平均薪资,
    sum(salary) 总薪资,
    count(gender) 人数
from emp group by dep;
#按照dep进行分组,然后去找或者计算select里面的字段


# 最低薪资小于2
mysql>:
select 
    dep 部门,
    group_concat(name) 成员,
    max(salary) 最高薪资,
    min(salary) 最低薪资,
    avg(salary) 平均薪资,
    sum(salary) 总薪资,
    count(gender) 人数
from emp group by dep having min(salary)<2;

#其实就是对上一步骤的再一次操作 把最低工资小于2的字段筛选出来,用到having

# having可以对 聚和结果 再进行筛选,where不可以

排序

排序规则
# order by 主排序字段 [asc|desc], 次排序字段1 [asc|desc], ...次排序字段n [asc|desc]
未分组状态下
mysql>: select * from emp;

# 按年龄升序
mysql>: select * from emp order by age asc;
# 按薪资降序
mysql>: select * from emp order by salary desc;

# 按薪资降序,如果相同,再按年龄降序
mysql>: select * from emp order by salary desc, age desc;
# 按龄降序,如果相同,再按薪资降序
mysql>: select * from emp order by age desc, salary desc;
分组状态下
# 最高薪资降序
mysql:
select 
    dep 部门,
    group_concat(name) 成员,
    max(salary) 最高薪资,
    min(salary) 最低薪资,
    avg(salary) 平均薪资,
    sum(salary) 总薪资,
    count(gender) 人数
from emp group by dep
order by 最高薪资 desc;

#分组状态下的语句是,先分组语句,在排序语句
#上面这句的意思是,先从emp中取值按dep进行分组,然后按照按select选择的字段进行展示,其中最高薪资是降序排列的。

限制 limit

# 语法:limit 条数  |  limit 偏移量,条数
mysql>: select name, salary from emp where salary<8 order by salary desc limit 1;

mysql>: select * from emp limit 5,3;  # 先偏移5条满足条件的记录,再查询3条(即当前查询表的数据是1-10,那么limit 5,3这句话的意思是从6开始到8)

多表查询

连接
# 连接:将有联系的多张表通过关联(有联系就行,不一定是外键)字段,进行连接,形成一张大表
# 连表查询:在大表的基础上进行查询,就称之为连表查询

# 将表与表建立连接的方式有四种:内连接、左连接、右连接、全连接

一对多数据准备

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;

#先看from后面的语句,就是说把emp这张表放到dep的左边,他们之间使用emp.dep_id和dep.id进行连接的,连接后的大表是按emp.id进行排列的,然后在按照select的内容进行展示

# 总结:只保留两个表有关联的数据

左连接

# 关键字: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;

小练习

### 基于上面的单表

#1.查询研发部山东人的平均薪资
select dep 部门, group_concat(name) 成员, avg(salary) 平均工资 from emp where dep='研发部' and area='山东';

#2.查询姓名中包含英文字母n并且居住在上海的人的所有信息
select * from emp where name like '%n%' and area='上海';

#3.查询姓名中包含英文字母n但不包含数字的人的所有信息

select * from emp where name like '%n' and not name regexp '.*[0-9]';

#4.查看各部门的平均年龄并升序排序
select avg(age) from emp group by dep order by age desc;

#5.查询各部门中年纪最大的人的姓名与居住地(户籍+区域)
select dep 部门, name 姓名, concat(area, '-', port) 居住地 from emp where (dep, age) in (select dep, max(age) from emp group by dep)

#6.查询不同年龄层次平均薪资大于5w组中工资最高者的姓名与薪资

# 先查询不同年龄层次平均薪资大于5w的组中的工资最高者,然后再从中选出姓名和薪资
select age, name, salary from emp where (age,salary) in (select age, max(salary) from emp group by age having avg(salary)>5)

#注意,上面的where(salary,age) 必须和 in中select的(max(salary),age)顺序对应,如果前面是salary,age,后面是max(salary),age,那么就会找到空
 
#7.查询每一个部门下的员工们及员工职责
select dep.name 部门名, dep.work 职责,group_concat(emp.name) from emp right join dep on emp.dep_id = dep.id group by dep_id;


#员工和部门是多对一的关系,如果员工们左连接,就会以员工表为准,这样就会有一个职责没有对应,而有个员工没有职责,显然不对,所以是右连接,保证每个职责与员工都会对应,

#通过id进行连接,然后按照员工id(多的一方) 进行排序,max的意思需要唯一确定一个,因为部门数据会重复,然后需要一个组合连接用来表示员工们

猜你喜欢

转载自www.cnblogs.com/michealjy/p/11588388.html