MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询

目录

一、单表查询

排序

聚合函数

分组

limit关键字

二、SQL约束

主键的自增

DELETE和TRUNCATE对自增长的影响

三、多表查询

外键约束

删除外键约束

多表查询的分类

内连接查询

外连接查询

第4节 合并查询

 UNION

第5节 子查询

子查询的结果作为查询条件

子查询的结果作为一张表

子查询结果是单列多行


一、单表查询

排序

通过 ORDER BY 子句,可以将查询出的结果进行排序(排序只是显示效果,不会影响真实数据)

  • 单列排序:只按照某一个字段进行排序, 就是单列排序

语法结构:SELECT 字段名 FROM 表名 [WHERE 字段 = 值] ORDER BY 字段名 [ASC / DESC]

需求1: 使用 salary 字段,对emp 表数据进行排序 (升序/降序)

ASC 表示升序排序(默认);DESC 表示降序排序

-- 默认升序排序 
ASC SELECT * FROM emp ORDER BY salary; 

-- 降序排序 
SELECT * FROM emp ORDER BY salary DESC;

  • 组合排序:同时对多个字段进行排序, 如果第一个字段相同 就按照第二个字段进行排序,以此类推

需求2:在薪水排序的基础上,再使用id进行排序, 如果薪水相同就以id 做降序排序

-- 组合排序 
SELECT * FROM emp ORDER BY salary DESC, eid DESC;

聚合函数

之前我们做的查询都是横向查询,它们都是根据条件一行一行的进行判断,而使用聚合函数查

询是纵向查询,它是对某一列的值进行计算,然后返回一个单一的值(另外聚合函数会忽略null空

值。)多变一

函数:方法,它封装了一些逻辑,比如给他一堆数据,特定函数可以返回最大值max(),avg()平

均值。求员工最高工资/平均工资/工资总和,都是聚合函数来做的。

聚合,也称为聚合统计或者聚合查询,就需要使用select关键字,有select 就得有from xxx

语法结构:SELECT 聚合函数(字段名) FROM 表名;

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第1张图片

#1 查询员工的总数 

-- 统计表中的记录条数 使用 count() 

SELECT COUNT(eid) FROM emp; -- 使用某一个字段 

SELECT COUNT(*) FROM emp; -- 使用 * 

SELECT COUNT(1) FROM emp; -- 使用 1,与 * 效果一样 

-- 下面这条SQL 得到的总条数不准确,因为count函数忽略了空值 

-- 所以使用时注意不要使用带有null的列进行统计 

SELECT COUNT(dept_name) FROM emp; 

#2 查看员工总薪水、最高薪水、最小薪水、薪水的平均值 

-- sum函数求和, max函数求最大, min函数求最小, avg函数求平均值 

SELECT

SUM(salary) AS '总薪水', 

MAX(salary) AS '最高薪水', 

MIN(salary) AS '最低薪水', 

AVG(salary) AS '平均薪水' 

FROM emp; 

#3 查询薪水大于4000员工的个数 

SELECT COUNT(*) FROM emp WHERE salary > 4000; 

#4 查询部门为'教学部'的所有员工的个数 

SELECT COUNT(*) FROM emp WHERE dept_name = '教学部';

#5 查询部门为'市场部'所有员工的平均薪水 

SELECT

AVG(salary) AS '市场部平均薪资' 

FROM emp 

WHERE dept_name = '市场部'; 

分组

分组往往和聚合函数一起时候,对数据进行分组,分完组之后在各个组内进行聚合统计分析

比如:求各个部门的员工数~

分组查询指的是使用 GROUP BY 语句,对查询的信息进行分组,相同数据作为一组.

语法格式:SELECT 分组字段/聚合函数 FROM 表名 GROUP BY 分组字段 [HAVING 条件]; 

#通过性别字段 进行分组,求各组的平均薪资
SELECT sex, AVG(salary) FROM emp GROUP BY sex;

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第2张图片

#1.查询每个部门的平均薪资 
SELECT dept_name,avg(salary) from emp GROUP BY dept_name;

#2.查询每个部门的平均薪资, 部门名称不能为null
SELECT dept_name,avg(salary) from emp WHERE dept_name is not null GROUP BY dept_name ;
  •  where 与 having的区别

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第3张图片

# 查询平均薪资大于6000的部门 -- 需要在分组后再次进行过滤,使用 having
SELECT dept_name,avg(salary) from emp WHERE dept_name is not null GROUP BY dept_name HAVING avg(salary)>6000;

limit关键字

limit是限制的意思,用于限制返回的查询结果的行数 (可以通过limit指定查询多少行数据)

limit 语法是 MySql的方言,用来完成分页.

语法结构:SELECT 字段1,字段2... FROM 表名 LIMIT offset , length;

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第4张图片

# 查询emp表中的前 5条数据 -- 参数1 起始值,默认是0 , 参数2 要查询的条数 
SELECT * FROM emp LIMIT 5; SELECT * FROM emp LIMIT 0 , 5; 

# 查询emp表中 从第4条开始,查询6条 -- 起始值默认是从0开始的. 
SELECT * FROM emp LIMIT 3 , 6;

-- 分页操作 每页显示3条数据 
SELECT * FROM emp LIMIT 0,3; -- 第1页 
SELECT * FROM emp LIMIT 3,3; -- 第2页 2-1=1 1*3=3 
SELECT * FROM emp LIMIT 6,3; -- 第三页 -- 分页公式 起始索引 = (当前页 - 1) * 每页条数

二、SQL约束

SQL语句来创建数据库约束

1)约束的作用:

对表中的数据进行进一步的限制,从而保证数据的正确性、有效性、完整性。违反约束的不正确数据,将无法插入到表中。

注意:约束是针对字段的

2)常见的约束MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第5张图片

3) 哪些字段可以作为主键 ?

通常针对业务去设计主键,往往每张表都设计一个主键主键是给数据库和程序使用的,跟最终的客户无关,所以主键没有意义没有关系,只要能够保证不重复就好,比如 身份证号列就可以作为主键。

另外,如果没有和业务关联太大的可以设计为主键的列的话,我们在进行数据库设计的时候往往人为加一列作为主键列,习惯上起名为id,rid等(下面的主键自增功能)。

主键约束

添加主键约束语法格式:字段名 字段类型 primary key

# 方式1 创建一个带主键的表 
CREATE TABLE emp2( 
-- 设置主键 唯一 非空 
eid INT PRIMARY KEY, 
ename VARCHAR(20),
sex CHAR(1) 
);

-- 删除表 
DROP TABLE emp2; 

-- 方式2 创建一个带主键的表 
CREATE TABLE emp2( 
eid INT , 
ename VARCHAR(20), 
sex CHAR(1), 
-- 指定主键为 eid字段 PRIMARY KEY(eid) 
);

-- 方式3 创建一个带主键的表 
CREATE TABLE emp2( 
eid INT , 
ename VARCHAR(20), 
sex CHAR(1) )
-- 创建的时候不指定主键,然后通过 DDL语句进行设置 
ALTER TABLE emp2 ADD PRIMARY KEY(eid);

  

删除主键约束

删除表中的主键约束 (了解)

-- 使用DDL语句 删除表中的主键 
ALTER TABLE emp2 DROP PRIMARY KEY; DESC emp2;

主键的自增

注: 主键如果让我们自己添加很有可能重复,我们通常希望在每次插入新记录时,数据库自动生成

主键字段的值

关键字: 

AUTO_INCREMENT 表示自动增长(字段类型必须是整数类型) 

-- 创建主键自增的表 
CREATE TABLE emp2( 
-- 关键字 AUTO_INCREMENT,主键类型必须是整数类型 
eid INT PRIMARY KEY AUTO_INCREMENT, 
ename VARCHAR(20), 
sex CHAR(1) 
);

修改主键自增的起始值

默认地 AUTO_INCREMENT 的开始值是 1,如果希望修改起始值,使用下面的方式就从那个值开始递增。

-- 创建主键自增的表,自定义自增其实值 
CREATE TABLE emp2( 
eid INT PRIMARY KEY AUTO_INCREMENT, 
ename VARCHAR(20), 
sex CHAR(1) )AUTO_INCREMENT=100;

DELETE和TRUNCATE对自增长的影响

删除表中所有数据有两种方式

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第6张图片

  • 非空约束

特点:某⼀列不允许为空

语法格式:字段名 字段类型 not null 

# 非空约束 
CREATE TABLE emp2( 
eid INT PRIMARY KEY AUTO_INCREMENT, 
-- 添加非空约束, ename字段不能为空 
ename VARCHAR(20) NOT NULL, 
sex CHAR(1) 
);

  • 唯一约束

特点: 表中的某一列的值不能重复( 对null不做唯一的判断 )

语法格式:字段名 字段值 unique 

#创建emp3表 为ename 字段添加唯一约束 
CREATE TABLE emp3( 
eid INT PRIMARY KEY AUTO_INCREMENT, 
ename VARCHAR(20) UNIQUE, 
sex CHAR(1) 
);

  • 默认值约束

含义:用来指定某列的默认值

语法格式:字段名 字段类型 DEFAULT 默认值

-- 创建带有默认值的表
CREATE TABLE emp4(
 eid INT PRIMARY KEY AUTO_INCREMENT,
 -- 为ename 字段添加默认值
 ename VARCHAR(20) DEFAULT '女', 
 sex CHAR(1)
);
  • 外键约束

FOREIGN KEY 表示外键约束,将在多表中学习。

三、多表查询

外键约束

主键:数据表A中有一列,这一列可以唯一的标识一条记录。

外键:数据表A中有一列,这一列指向了另外一张数据表B的主键。

3.1.1 什么是外键

外键指的是在从表中与主表的主键对应的那个字段,比如员工表的 dept_id,就是外键。使用外键约束可以让两张表之间产生一个对应关系,从而保证主从表的引用的完整性。

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第7张图片

  • 多表关系中的主表和从表

主表: 主键id所在的表, 约束别人的表

从表: 外键所在的表多, 被约束的表

创建外键约束语法格式

1. 新建表时添加外键

[CONSTRAINT] [外键约束名称] FOREIGN KEY(外键字段名) REFERENCES 主表名(主键字 

段名) 

-- 重新创建 employee表,添加外键约束 
CREATE TABLE employee( 
eid INT PRIMARY KEY AUTO_INCREMENT, 
ename VARCHAR(20), 
age INT, 
dept_id INT, 

-- 外键字段类型要和主表的主键字段类型保持一致 
-- 添加外键约束 
constraint emp_dept_fk foreign key(dept_id) references department(id) 
);

2.已有表添加外键

ALTER TABLE 从表 ADD [CONSTRAINT] [外键约束名称] FOREIGN KEY (外键字段名) 

REFERENCES 主表(主 键字段名);

删除外键约束

语法格式:alter table 从表 drop foreign key 外键约束名称

注:添加/删除外键针对的都是从表。

再将外键添加回来语法格式:

ALTER TABLE 从表 ADD [CONSTRAINT] [外键约束名称] FOREIGN KEY (外键字段名) 

REFERENCES 主表(主 键字段名);

-- 删除employee 表中的外键约束,外键约束名 emp_dept_fk 
ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;


-- 可以省略外键名称, 系统会自动生成一个 
ALTER TABLE employee ADD FOREIGN KEY (dept_id) REFERENCES department (id);

外键约束的注意事项

1) 从表外键类型必须与主表主键类型一致 否则创建失败.

2) 添加数据时, 应该先添加主表中的数据.

3) 删除数据时,应该先删除从表中的数据.

如果想实现删除主表数据的同时,也删除掉从表数据,可以使用级联删除操作。

语法格式:ON DELETE CASCADE 

-- 重新创建添加级联操作 
CREATE TABLE employee( 
eid INT PRIMARY KEY AUTO_INCREMENT, 
ename VARCHAR(20), 
age INT,
dept_id INT,
CONSTRAINT emp_dept_fk FOREIGN KEY(dept_id) REFERENCES department(id) 
-- 添加级联删除 
ON DELETE CASCADE 
);

多表查询的分类

笛卡尔积

交叉连接查询,因为会产生笛卡尔积,所以 基本不会使用

1) 语法格式:SELECT 字段名 FROM 表1, 表2;

-- 查询所有商品信息和对应的分类信息

SELECT * FROM category , products;

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第8张图片 需要添加where条件,过滤出有效数据

注:假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1),(b, 2)}。  

内连接查询

内连接的特点:通过指定的条件去匹配两张表中的数据, 匹配上就显示,匹配不上就不显示。

比如通过: 从表的外键 = 主表的主键 方式去匹配

  • 1) 隐式内链接

form子句后面直接写多个表名,使用where指定连接条件的 这种连接方式是隐式内连接,

使用where条件过滤无用的数据。

语法格式:SELECT 字段名 FROM 左表, 右表 WHERE 连接条件;

-- 查询商品表的商品名称和商品的分类信息
#隐式内连接(笛卡尔积 +where条件),另通过给表起别名的方式, 方便我们的查询
SELECT * FROM category c, products p where c.cid=p.category_id;

#笛卡尔积 +where条件实现家电分类下的所有产品
SELECT * FROM category c, products p where c.cid=p.category_id and cname = '家电';

#查询 格力空调是属于哪一分类下的商品
SELECT * FROM category c, products p where c.cid=p.category_id and pname='格力空调';

  • 2) 显式内连接

使用 inner join ...on 这种方式, 就是显式内连接

语法格式:SELECT 字段名 FROM 左表 [INNER] JOIN 右表 ON 条件 

-- inner 可以省略 

#查询所有商品信息和对应的分类信息
SELECT * from category c inner JOIN products p on c.cid=p.category_id;

# 查询鞋服分类下,价格大于500的商品名称和价格 
-- 我们需要确定的几件事 
-- 1.查询几张表 products & category 
-- 2.表的连接条件 从表.外键 = 主表的主键 
-- 3.查询的条件 cname = '鞋服' and price > 500 
-- 4.要查询的字段 pname price

SELECT p.pname, p.price FROM products p INNER JOIN category c ON p.category_id = c.cid WHERE p.price > 500 AND cname = '鞋服';

SELECT * from category c inner JOIN products p on c.cid=p.category_id where price >500 and cname='鞋服';

外连接查询

  • 1) 左外连接(主要使用)

左外连接 , 使用 LEFT OUTER JOIN , OUTER 可以省略

左外连接的特点:以左表为基准, 匹配右边表中的数据,如果匹配的上,就展示匹配到的数据。如果匹配不到, 左表中的数据正常展示, 右边的展示为null.

 语法格式:SELECT 字段名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 条件 

# 查询每个分类下的商品个数 
/* 
1.连接条件: 主表.主键 = 从表.外键 
2.查询条件: 每个分类 需要分组 
3.要查询的字段: 分类名称, 分类下商品个数,用统计函数
*/

SELECT c.cname  AS '分类名称', COUNT(p.pid) AS '商品个数' FROM category c LEFT JOIN products p ON c.cid = p.category_id GROUP BY c.cname;

  • 2) 右外连接

右外连接 , 使用 RIGHT OUTER JOIN , OUTER 可以省略

右外连接的特点:以右表为基准,匹配左边表中的数据,如果能匹配到,展示匹配到的数据。如果匹配不到,右表中的数据正常展示, 左边展示为null

语法格式:SELECT 字段名 FROM 左表 RIGHT [OUTER ]JOIN 右表 ON 条件

-- 左外连接查询 
SELECT * FROM category c LEFT JOIN products p ON c.`cid`= p.`category_id`;

-- 右外连接查询 
SELECT * FROM products p RIGHT JOIN category c ON p.`category_id` = c.`cid`;

第4节 合并查询

 UNION

UNION 操作符用于合并两个或多个 SELECT 语句的结果集,并消除重复行。

注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同

时,每条 SELECT 语句中的列的顺序必须相同。

UNION 子句的基本语法如下所示:

  

SELECT Id,NAME,Amount,Date 

FROM customers 

LEFT JOIN orders 

on customers.Id = orders.Customers_Id 

UNION 

SELECT Id,NAME,Amount,Date 

from customers 

RIGHT JOIN orders 

on customers.Id = orders.Customers_Id;

注意:UNION和UNION ALL关键字都是将两个结果集合并为一个,也有区别。

1、重复值:UNION在进行表连接后会筛选掉重复的记录,而Union All不会去除重复记录。2、UNION ALL只是简单的将两个结果合并后就返回。

3、在执行效率上,UNION ALL 要比UNION快很多,因此,若可以确认合并的两个结果集中不

包含重复数据,那么就使用UNION ALL。 

第5节 子查询

子查询概念:一条select 查询语句的结果, 作为另一条 select 语句的一部分

子查询的特点:子查询必须放在小括号中;子查询的场景中还会有另外一个特点,整个sql至少会有两个select关键字。

子查询常见分类

  • where型 子查询: 将子查询的结果, 作为父查询的比较条件 =
  • from型 子查询 : 将子查询的结果, 作为 一张表,提供给父层查询使用
  • exists型 子查询: 子查询的结果是单列多行, 类似一个数组, 父层查询使用 IN 函数 ,包含子查询的结果

子查询的结果作为查询条件

语法格式:SELECT 查询字段 FROM 表 WHERE 字段=(子查询); 

# 通过子查询的方式, 查询价格最高的商品信息 
-- 1.先查询出最高价格 
SELECT MAX(price) FROM products; 
-- 2.将1中得出的最高价格作为条件,获取商品信息(本来是数字,用sql语句代替)
SELECT * FROM products WHERE price = (SELECT MAX(price) FROM products);


#查询化妆品分类下的 商品名称 商品价格 
-- 先查出化妆品分类的 id 
SELECT cid FROM category WHERE cname = '化妆品'; 
-- 根据分类id ,去商品表中查询对应的商品信息 
SELECT p.pname, p.price FROM products p WHERE p.category_id= (SELECT cid FROM category WHERE cname = '化妆品');


#查询小于平均价格的商品信息
-- 1.查询平均价格 
SELECT AVG(price) FROM products; -- 1866 
-- 2.查询小于平均价格的商品 
SELECT * FROM products WHERE price < (SELECT AVG(price) FROM products);

子查询的结果作为一张表

语法格式:SELECT 查询字段 FROM (子查询)表别名 WHERE 条件; 

注意: 当子查询作为一张表的时候,需要起别名,否则无法访问表中的字段。

-- 1. 先查询分类表的数据 
SELECT * FROM category; 

-- 2.将上面的查询语句 作为一张表使用 
SELECT p.pname, 
p.price, 
c.cname 
FROM products p 
-- 子查询作为一张表使用时 要起别名 才能访问表中字段 
INNER JOIN (SELECT * FROM category) c ON 
p.category_id = c.cid WHERE p.price > 500;

子查询结果是单列多行

子查询的结果类似一个数组, 父层查询使用 IN 函数 ,包含子查询的结果

语法格式:SELECT 查询字段 FROM 表 WHERE 字段 IN (子查询); 

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第9张图片

MySQL核心查询-排序 分组 聚合 多表查询 合并查询 子查询_第10张图片

# 查询价格小于两千的商品,来自于哪些分类(名称) 
-- 先查询价格小于2000 的商品的,分类ID 
SELECT DISTINCT category_id FROM products WHERE price < 2000; 

-- 在根据分类的id信息,查询分类名称 
-- 子查询获取的是单列多行数据
SELECT * FROM category WHERE cid in (SELECT DISTINCT category_id FROM products WHERE price < 2000);

# 查询家电类 与 鞋服类下面的全部商品信息 
-- 先查询出家电与鞋服类的 分类ID 
SELECT cid FROM category WHERE cname IN ('家电','鞋服'); 
-- 根据cid 查询分类下的商品信息 
SELECT * FROM products WHERE category_id IN (SELECT cid FROM category WHERE cname IN ('家电','鞋 服'));

子查询总结:

1. 子查询如果查出的是一个字段(单列), 那就在where后面作为条件使用. 

单列单行 =

单列多行 in

2. 子查询如果查询出的是多个字段(多列), 就当做一张表使用(要起别名).

你可能感兴趣的:(mysql,mysql,数据库)