MySQL入门学习:约束、DQL和多表操作

一、Mysql的约束

(一)简介

​ 在设计表的时候,为了保证表中数据的完整性、有效性,比如用户表有些列的值(手机号)不能为空,有些列的值(身份证号)不能重复。

​ MySQL中常用的约束有以下几类:

  • 主键约束(primary key) PK
  • 自增长约束(auto_increment)
  • 非空约束(not null)
  • 唯一性约束(unique)
  • 默认约束(default)
  • 零填充约束(zerofill)
  • 外键约束(foreign key) FK

(二)主键约束

主键约束的特点:

  • MySQL主键约束是一个列或者多个列的组合,其值能唯一地标识表中的每一行,方便在RDBMS中尽快的找到某一行。
  • 主键约束相当于 唯一约束 + 非空约束 的组合,主键约束列不允许重复,也不允许出现空值。
  • 每个表最多只允许一个主键
  • 主键约束的关键字是:primary key
  • 当创建主键的约束时,系统默认会在所在的列和列组合上建立对应的唯一索引。

(三)单列主键

创建主键的语法:

语法1:

create table 表名(
   ...
   <字段名> <数据类型> primary key 
   ...
)

语法2:

create table 表名(
   ...
   [constraint <约束名>] primary key [字段名]
);

(四)联合主键

联合主键也就是一张表中的多个字段共同构成一个主键;

语法:

create table 表名(
   ...
   primary key (字段1,字段2,…,字段n)
);

(五)通过修改表结构添加主键

语法:

create table 表名(
   ...
);
alter table <表名> add primary key(字段列表);

删除主键语法:

alter table <数据表名> drop primary key;

(六)自增长约束

1、基本内容

​ 在 MySQL 中,当主键定义为自增长后,这个主键的值就不再需要用户输入数据了,而由数据库系统根据定义自动赋值。每增加一条记录,主键会自动以相同的步长进行增长,通过给字段添加 auto_increment 属性来实现主键自增长。

语法:

字段名 数据类型 auto_increment

自增长约束的特点:

  • 默认情况下,auto_increment的初始值是 1,每新增一条记录,字段值自动加 1。
  • 一个表中只能有一个字段使用 auto_increment约束,且该字段必须有唯一索引,以避免序号重复(即为主键或主键的一部分)。
  • auto_increment约束的字段必须具备 NOT NULL 属性。
  • auto_increment约束的字段只能是整数类型(TINYINT、SMALLINT、INT、BIGINT 等。
  • auto_increment约束字段的最大值受该字段的数据类型约束,如果达到上限,auto_increment就会失效。

2、指定自增字段初始值

​ 如果第一条记录设置了该字段的初始值,那么新增加的记录就从这个初始值开始自增。

方式1,创建表时指定:

create table 表名 ( 
  字段1 int primary key auto_increment, 
  字段2 varchar(20)
)auto_increment=100;

方式2,创建表之后指定:

create table 表名 ( 
  字段1 int primary key auto_increment, 
  字段2 varchar(20)
);
alter table 表名 auto_increment=100;

3、delete和truncate在删除后自增列的变化

  • delete数据之后自动增长从断点开始
  • truncate数据之后自动增长从默认起始值开始

(七)非空约束

​ MySQL 非空约束(not null)指字段的值不能为空。对于使用了非空约束的字段,如果用户在添加数据时没有指定值,数据库系统就会报错。

语法:

方式1:<字段名><数据类型> not null;
方式2:alter table 表名 modify 字段 类型 not null;

删除非空约束:

alter table 表名 modify 字段 类型 

(八)唯一约束

​ 唯一约束(Unique Key)是指所有记录中字段的值不能重复出现。例如,为 id 字段加上唯一性约束后,每条记录的 id 值都是唯一的,不能出现重复的情况。

语法:

方式1:<字段名> <数据类型> unique
方式2: alter table 表名 add constraint 约束名 unique(列)

删除唯一约束的语法:

alter table <表名> drop index <唯一约束名>;

(九)默认约束

​ MySQL 默认值约束用来指定某列的默认值。

语法:

方式1: <字段名> <数据类型> default <默认值>;
方式2: alter table 表名 modify 列名 类型 default 默认值; 

删除默认约束:

alter table <表名> modify column <字段名> <类型> default null; 

二、基本操作-DQL

​ 数据库管理系统一个重要功能就是数据查询,数据查询不应只是简单返回数据库中存储的数据,还应该根据需要对数据进行筛选以及确定数据以什么样的格式显示。

语法:

select 
  [all|distinct]
  <目标列的表达式1> [别名],
  <目标列的表达式2> [别名]...
from <表名或视图名> [别名],<表名或视图名> [别名]...
[where<条件表达式>]
[group by <列名> 
[having <条件表达式>]]
[order by <列名> [asc|desc]]
[limit <数字或者列表>];

为了后续的实操,创建product表,并往表中插入相应数据:

insert into product values(null,'海尔洗衣机',5000,'c001');
insert into product values(null,'美的冰箱',3000,'c001');
insert into product values(null,'格力空调',5000,'c001');
insert into product values(null,'九阳电饭煲',200,'c001');
insert into product values(null,'啄木鸟衬衣',300,'c002');
insert into product values(null,'恒源祥西裤',800,'c002');
insert into product values(null,'花花公子夹克',440,'c002');
insert into product values(null,'劲霸休闲裤',266,'c002');
insert into product values(null,'海澜之家卫衣',180,'c002');
insert into product values(null,'杰克琼斯运动裤',430,'c002');
insert into product values(null,'兰蔻面霜',300,'c003');
insert into product values(null,'雅诗兰黛精华水',200,'c003');
insert into product values(null,'香奈儿香水',350,'c003');
insert into product values(null,'SK-II神仙水',350,'c003');
insert into product values(null,'资生堂粉底液',180,'c003');
insert into product values(null,'老北京方便面',56,'c004');
insert into product values(null,'良品铺子海带丝',17,'c004');
insert into product values(null,'三只松鼠坚果',88,null);

简单查询:

-- 1.查询所有的商品.  
select *  from product;
-- 2.查询商品名和商品价格. 
select pname,price from product;
-- 3.别名查询.使用的关键字是as(as可以省略的).  
-- 3.1表别名: 
select * from product as p;
-- 3.2列别名:
select pname as pn from product; 
-- 4.去掉重复值.  
select distinct price from product;
-- 5.查询结果是表达式(运算查询):将所有商品的价格+10元进行显示.
select pname,price+10 from product;

(一)运算符

1、四大类运算符

算术运算符 说明
+ 加法运算
- 减法运算
***** 乘法运算
/ DIV 除法运算,返回商
% MOD 求余运算,返回余数
比较运算符 说明
= 等于
< <= 小于和小于等于
> >= 大于和大于等于
<=> 安全的等于,两个操作码均为NULL时,其所得值为1;而当一个操作码为NULL时,其所得值为0
<> **!=** 不等于
IS NULL ISNULL 判断一个值是否为 NULL
IS NOT NULL 判断一个值是否不为 NULL
LEAST 当有两个或多个参数时,返回最小值
GREATEST 当有两个或多个参数时,返回最大值
BETWEEN AND 判断一个值是否落在两个值之间
IN 判断一个值是IN列表中的任意一个值
NOT IN 判断一个值不是IN列表中的任意一个值
LIKE 通配符匹配
REGEXP 正则表达式匹配
逻辑运算符 说明
NOT 或者 ! 逻辑非
AND 或者 && 逻辑与
OR 或者 || 逻辑或
XOR 逻辑异或
位运算符 说明
| 按位或
& 按位与
^ 按位异或
<< 按位左移
>> 按位右移
~ 按位取反,反转所有比特

2、运算符操作

-- 查询商品名称为“海尔洗衣机”的商品所有信息:
select * from product where pname = '海尔洗衣机';

-- 查询价格为800商品
select * from product where price = 800;

-- 查询价格不是800的所有商品
select * from product where price != 800;
select * from product where price <> 800;
select * from product where not(price = 800);

-- 查询商品价格大于60元的所有商品信息
select * from product where price > 60;

-- 查询商品价格在200到1000之间所有商品
select * from product where price >= 200 and price <=1000;
select * from product where price between 200 and 1000;

-- 查询商品价格是200或800的所有商品
select * from product where price = 200 or price = 800;
select * from product where price in (200,800);
 
-- 查询含有‘裤'字的所有商品
select * from product where pname like ‘%裤%';
 
-- 查询以'海'开头的所有商品
select * from product where pname like '海%';
 
-- 查询第二个字为'蔻'的所有商品
select * from product where pname like '_蔻%';
 
-- 查询category_id为null的商品
select * from product where category_id is null;
 
-- 查询category_id不为null分类的商品
select * from product where category_id is not null;

-- 使用least求最小值
select least(10, 20, 30); -- 10
select least(10, null , 30); -- null
 
-- 使用greatest求最大值
select greatest(10, 20, 30);
select greatest(10, null, 30); -- null

(二)排序查询

​ 如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 order by 子句来设定你想按哪个字段哪种方式来进行排序,再返回搜索结果。

语法:

select 
 字段名1,字段名2,……
from 表名
order by 字段名1 [asc|desc],字段名2[asc|desc]……

注意:

  • asc代表升序,desc代表降序,如果不写默认升序
  • order by用于子句中可以支持单个字段,多个字段,表达式,函数,别名
  • order by子句,放在查询语句的最后面。LIMIT子句除外
-- 1.使用价格排序(降序)
select * from product order by price desc;
-- 2.在价格排序(降序)的基础上,以分类排序(降序)
select * from product order by price desc,category_id asc;
-- 3.显示商品的价格(去重复),并排序(降序)
select distinct price from product order by price desc;

(三)聚合查询

1、介绍

​ 前面所进行的查询都是横向查询,都是根据条件一行一行的进行判断,而使用聚合函数查询是纵向查询,它是对一列的值进行计算,然后返回一个单一的值;另外聚合函数会忽略空值。

聚合函数 作用
count() 统计指定列不为NULL的记录行数;
sum() 计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0
max() 计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
min() 计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
avg() 计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0

案例:

-- 1 查询商品的总条数
select count(*) from product;
-- 2 查询价格大于200商品的总条数
select count(*) from product where price > 200;
-- 3 查询分类为'c001'的所有商品的总和
select sum(price) from product where category_id = 'c001';
-- 4 查询商品的最大价格
select max(price) from product;
-- 5 查询商品的最小价格
select min(price) from product;
-- 6 查询分类为'c002'所有商品的平均价格
select avg(price) from product where category_id = 'c002';

2、聚合函数对null的处理

  • count函数对null值的处理:如果count函数的参数为星号(*),则统计所有记录的个数。而如果参数为某字段,不统计含null值的记录个数。
  • sum和avg函数对null值的处理:这两个函数忽略null值的存在,就好象该条记录不存在一样。
  • max和min函数对null值的处理:max和min两个函数同样忽略null值的存在。

(四)分组查询

​ 分组查询是指使用group by字句对查询信息进行分组,如果要进行分组的话,则SELECT子句之后,只能出现分组的字段和统计函数,其他的字段不能出现:

语法:

select 字段1,字段2… from 表名 group by 分组字段 having 分组条件;

分组条件筛选having:

  • 分组之后对统计结果进行筛选的话必须使用having,不能使用where
  • where子句用来筛选 FROM 子句中指定的操作所产生的行
  • group by 子句用来分组 WHERE 子句的输出。
  • having 子句用来从分组的结果中筛选行

(五)分页查询

​ 分页查询在项目开发中常见,由于数据量很大,显示屏长度有限,因此对数据需要采取分页显示方式。例如数据共有30条,每页显示5条,第一页显示1-5条,第二页显示6-10条。

语法:

-- 方式1-显示前n条
select 字段1,字段2... from 表明 limit n
-- 方式2-分页显示
select 字段1,字段2... from 表明 limit m,n
m: 整数,表示从第几条索引开始,计算方式 (当前页-1)*每页显示条数
n: 整数,表示查询多少条数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XzEjfRAk-1689301955844)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713110651123.png)]

(六)将一张表的数据导入另一张表

1、INSERT INTO SELECT

语法:

insert into Table2(field1,field2,…) select value1,value2,… from Table1 或者:
insert into Table2 select * from Table1

注意:使用INSERT INTO SELECT时,要求目标表Table2必须存在;

2、SELECT INTO FROM

语法:

SELECT vale1, value2 into Table2 from Table1

注意:使用SELECT INTO FROM时,要求目标表Table2不存在,因为在插入时会自动创建表Table2,并将Table1中指定字段数据复制到Table2中。

(七)正则表达式

​ 正则表达式(regular expression)描述了一种字符串匹配的规则,正则表达式本身就是一个字符串,使用这个字符串来描述、用来定义匹配规则,匹配一系列符合某个句法规则的字符串。在开发中,正则表达式通常被用来检索、替换那些符合某个规则的文本。MySQL通过REGEXP关键字支持正则表达式进行字符串匹配。

模式 描述
^ 匹配输入字符串的开始位置。
$ 匹配输入字符串的结束位置。
. 匹配除 “\n” 之外的任何单个字符。
[…] 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。
[^…] 负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’。
p1|p2|p3 匹配 p1 或 p2 或 p3。例如,‘z|food’ 能匹配 “z” 或 “food”。‘(z|f)ood’ 则匹配 “zood” 或 “food”。
***** 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 **“zoo”*** 等价于**{0,}****。**
+ 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。

案例:

1)匹配以某字符串开头的记录:

select * from product where pname regexp '^花';

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U6BOFCMN-1689301955846)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713112752308.png)]

2)匹配以某字符串结尾的记录:

selet * from product where pname regexp '裤$';

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UVRrENcH-1689301955847)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713113000059.png)]

3)匹配指定字符且其前面有字符的记录,匹配指定字符且其后有指定字符的记录:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kVtbRjU0-1689301955848)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713114413086.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hoD7Y5ss-1689301955850)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713114459522.png)]

-- [^...] 注意^符合只有在[]内才是取反的意思,在别的地方都是表示开始处匹配
SELECT  'a' REGEXP '[^abc]';
SELECT  'x' REGEXP '[^abc]';
SELECT  'abc' REGEXP '[^a]';

-- a* 匹配0个或多个a,包括空字符串。 可以作为占位符使用.有没有指定字符都可以匹配到数据

SELECT 'stab' REGEXP '.ta*b';
SELECT 'stb' REGEXP '.ta*b';
SELECT '' REGEXP 'a*';

-- a+  匹配1个或者多个a,但是不包括空字符
SELECT 'stab' REGEXP '.ta+b';
SELECT 'stb' REGEXP '.ta+b';

-- a?  匹配0个或者1个a
SELECT 'stb' REGEXP '.ta?b';
SELECT 'stab' REGEXP '.ta?b';
SELECT 'staab' REGEXP '.ta?b';
 
-- a1|a2  匹配a1或者a2,
SELECT 'a' REGEXP 'a|b';
SELECT 'b' REGEXP 'a|b';
SELECT 'b' REGEXP '^(a|b)';
SELECT 'a' REGEXP '^(a|b)';
SELECT 'c' REGEXP '^(a|b)';
 
-- a{m} 匹配m个a
 
SELECT 'auuuuc' REGEXP 'au{4}c';
SELECT 'auuuuc' REGEXP 'au{3}c';

 -- a{m,n} 匹配m到n个a,包含m和n
 
SELECT 'auuuuc' REGEXP 'au{3,5}c';
SELECT 'auuuuc' REGEXP 'au{4,5}c';
SELECT 'auuuuc' REGEXP 'au{5,10}c';
 
-- (abc) abc作为一个序列匹配,不用括号括起来都是用单个字符去匹配,如果要把多个字符作为一个整体去匹配就需要用到括号,所以括号适合上面的所有情况。
SELECT 'xababy' REGEXP 'x(abab)y';
SELECT 'xababy' REGEXP 'x(ab)*y';
SELECT 'xababy' REGEXP 'x(ab){1,2}y';

三、多表操作

​ 实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系,接下来我们将在单表的基础上,一起学习多表方面的知识。

(一)多表关系

  • 一对一关系
  • 一对多关系/多对一关系
  • 多对多关系

(二)外键约束

1、介绍

​ MySQL 外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表(父表),外键所在的表就是从表(子表)。外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。比如,一个水果摊,只有苹果、桃子、李子、西瓜等 4 种水果,那么,你来到水果摊要买水果就只能选择苹果、桃子、李子和西瓜,其它的水果都是不能购买的。

特点:

  • 主表必须已经存在于数据库中,或者是当前正在创建的表。

  • 必须为主表定义主键。

  • 主键不能包含空值,但允许在外键中出现空值。也就是说,只要外键的每个非空值出现在指定的主键中,这 个外键的内容就是正确的。

  • 在主表的表名后面指定列名或列名的组合。这个列或列的组合必须是主表的主键或候选键。

  • 外键中列的数目必须和主表的主键中列的数目相同。

  • 外键中列的数据类型必须和主表主键中对应列的数据类型相同。

2、外键约束的创建

方式1:创建表的时候设置外键约束

语法:

[constraint <外键名>] foreign key 字段名 [,字段名2,…] references <主表名> 主键列1 [,主键列2,…]

案例:

-- 创建一个部门表
create table if not exists dept(
  deptno varchar(20) primary key ,  -- 部门号
  name varchar(20) -- 部门名字
);

-- 创建员工表
create table if not exists emp(
  eid varchar(20) primary key , -- 员工编号
  ename varchar(20), -- 员工名字
  age int,  -- 员工年龄
  dept_id varchar(20),  -- 员工所属部门
  constraint emp_fk foreign key (dept_id) references dept (deptno) -- 外键约束
);

方式2:修改表时添加外键约束

语法:

alter table <数据表名> add constraint <外键名> foreign key(<列名>) references <主表名> (<列名>);

案例:

-- 创建部门表
create table if not exists dept2(
  deptno varchar(20) primary key ,  -- 部门号
  name varchar(20) -- 部门名字
);
-- 创建员工表
create table if not exists emp2(
  eid varchar(20) primary key , -- 员工编号
  ename varchar(20), -- 员工名字
  age int,  -- 员工年龄
  dept_id varchar(20)  -- 员工所属部门

);
-- 创建外键约束
alter table emp2 add constraint dept_id_fk foreign key(dept_id) references dept2 (deptno);

3、外键约束下数据的插入

对于存在外键约束的两张表,必须先对主表进行数据插入。

-- 给主表(部门表)插入数据
insert into dept values('1001','研发部');
insert into dept values('1002','销售部');
insert into dept values('1003','财务部');
insert into dept values('1004','人事部');
-- 给从表(员工表)插入数据,注意给从表添加数据时,外键列的值不能随便写,必须依赖主表的主键列
insert into emp values('1','乔峰',20, '1001');
insert into emp values('2','段誉',21, '1001');
insert into emp values('3','虚竹',23, '1001');
insert into emp values('4','阿紫',18, '1002');
insert into emp values('5','扫地僧',35, '1002');
insert into emp values('6','李秋水',33, '1003');
insert into emp values('7','鸠摩智',50, '1003'); 

– 主表中不存在的外键约束,在从表中插入相应数据时是不允许的

insert into emp values('8','天山童姥',60, '1005');  -- 不可以

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8hJyerVV-1689301955851)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713151426903.png)]

改成主表中存在的外键约束的列名,则可以成功:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g6cHLDYQ-1689301955852)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713151507526.png)]

4、外键约束下数据的删除

  • 主表的数据被从表依赖时,不能删除,否则可以删除
  • 从表的数据可以随便删除

5、删除外键约束

当一个表中不需要外键约束时,就需要从表中将其删除。外键一旦删除,就会解除主表和从表间的关联关系

语法:

-- 直接删除从表中的约束键
alter table <表名> drop foreign key <外键约束名>;

6、多对多表的外键约束

多对多表的外键约束创建和一对多表的外键约束创建是一样的,接下来直接上案例。

案例:

-- 学生表和课程表(多对多)
  -- 1 创建学生表student(左侧主表)
   create table if not exists student(
    sid int primary key auto_increment,
    name varchar(20),
    age int,
    gender varchar(20)
   );
  -- 2 创建课程表course(右侧主表)
  create table course(
   cid  int primary key auto_increment,
   cidname varchar(20)
  );

-- 3创建中间表student_course/score(从表)
  create table score(
    sid int,
    cid int,
    score double
  );
    
-- 4建立外键约束(2次)
alter table score add foreign key(sid) references student(sid);
alter table score add foreign key(cid) references course(cid);
 
-- 5给学生表添加数据
insert into student values(1,'小龙女',18,'女'),(2,'阿紫',19,'女'),(3,'周芷若',20,'男');
-- 6给课程表添加数据
insert into course values(1,'语文'),(2,'数学'),(3,'英语');
-- 7给中间表添加数据
insert into score values(1,1,70),(1,2,82),(2,1,90),(2,3,86),(3,2,76),(3,3,80);

(三)多表联合查询

1、介绍

​ 多表查询就是同时查询两个或两个以上的表,因为有的时候用户在查看数据的时候,需要显示的数据来自多张表,多表查询有以下分类:

  • 交叉连接查询 [产生笛卡尔积,了解]

    语法:

    select * from A,B;
    
  • 内连接查询(使用的关键字 inner join – inner可以省略

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ughmMhcZ-1689301955853)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713155339808.png)]

    隐式内连接(SQL92标准)语法:

    select * from A,B where 条件;
    

    显示内连接(SQL99标准)语法:

    select * from A inner join B on 条件;
    
  • 外连接查询(使用的关键字 outer join – outer可以省略)

    左外连接:left outer join

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ZE3Bih7-1689301955854)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713155359274.png)]

    select * from A left outer join B on 条件;
    

    右外连接:right outer join

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NkAud6O6-1689301955855)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713155404917.png)]

    select * from A right outer join B on 条件;
    

    满外连接: full outer join

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IuzHJkiH-1689301955855)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713155410342.png)]

    select * from A full outer join B on 条件;
    
  • 子查询

    select的嵌套

  • 表自关联:

    将一张表当成多张表来用

2、联合查询操作

交叉连接查询

特点:

  • 交叉连接查询返回被连接的两个表所有数据行的笛卡尔积;
  • 笛卡尔积可以理解为一张表的每一行去和另外一张表的任意一行进行匹配;
  • 假如A表有m行数据,B表有n行数据,则返回m*n行数据;
  • 笛卡尔积会产生很多冗余的数据,后期的其他查询可以在该集合的基础上进行条件筛选。

例子:交叉查询dept和emp两张表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VQXcSmcq-1689301955856)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713160447354.png)]

内连接查询

隐式内连接查询例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i0fDuLNG-1689301955857)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713162036996.png)]

显式内连接查询例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qqSfGVcb-1689301955857)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713161618483.png)]

外连接查询

左外连接查询例子:

select * from emp a left join dept b on a.dept_id = b.deptno where b.deptno is null;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mXC74hpY-1689301955858)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713170922157.png)]

右外连接查询例子:

select * from emp a right join dept b on a.dept_id = b.deptno where a.dept_id is null;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HfUCNiX5-1689301955859)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713171008649.png)]

子查询

​ 子查询就是指的在一个完整的查询语句之中,嵌套若干个不同功能的小查询,从而一起完成复杂查询的一种编写形式,通俗一点就是包含select嵌套的查询。

子查询类型:

  • 单行单列:返回的是一个具体列的内容,可以理解为一个单值数据;

    例子:

    -- 查询年龄最大的员工信息,包含员工姓名、年龄、部门id和部门名称
    select ename,age,dept_id,name from emp a left join dept b on a.dept_id = b.deptno where age = (select max(age) from emp);
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kSmwuhpO-1689301955860)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713172023478.png)]

  • 单行多列:返回一行数据中多个列的内容;

  • 多行单列:返回多行记录之中同一列的内容,相当于给出了一个操作范围;

    -- 查询财务部和人事部的员工信息,包括员工姓名和所属部门id
    select ename,dept_id from emp where dept_id in (select deptno from dept where name in ('财务部', '人事部'));
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aDo1zxBO-1689301955861)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230713172309376.png)]

  • 多行多列:查询返回的结果是一张临时表

​ 在子查询中,有一些常用的逻辑关键字,这些关键字可以给我们提供更丰富的查询功能,主要关键字如下:

  • ALL关键字

    ALL与子查询返回的所有值比较为true 则返回true;ALL可以与=、>、>=、<、<=、<>结合是来使用,分别表示等于、大于、大于等于、小于、小于等于、不等于其中的其中的所有数据。
    ALL表示指定列中的值必须要大于子查询集的每一个值,即必须要大于子查询集的最大值;如果是小于号即小于子查询集的最小值。同理可以推出其它的比较运算符的情况。

    语法:

    select …from …where c > all(查询语句)
    --等价于:
    select ...from ... where c > result1 and c > result2 and c > result3
    

    案例:

    -- 查询其他部门年龄比1003部门最大年龄大的员工信息
    select * from emp where age > all(select age from emp where dept_id = '1003');
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWqvTLic-1689301955861)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230714100609926.png)]

  • ANY和SOME关键字

    ANY:与子查询返回的任何值比较为true 则返回true;ANY可以与=、>、>=、<、<=、<>结合是来使用,分别表示等于、大于、大于等于、小于、小于等于、不等于其中的其中的任何一个数据。
    表示指定列中的值要大于子查询中的任意一个值,即必须要大于子查询集中的最小值。同理可以推出其它的比较运算符的情况。
    SOME和ANY的作用一样,SOME可以理解为ANY的别名

    语法:

    select …from …where c > any(查询语句)
    --等价于:
    select ...from ... where c > result1 or c > result2 or c > result3
    

    案例:

    -- 查询其他部门任意一个比1003部门年龄小的员工信息
    select * from emp where age > any(select age from emp where dept_id = '1003');
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjCjfaBd-1689301955862)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230714100628727.png)]

  • IN关键字

    IN关键字,用于判断某个记录的值,是否在指定的集合中;在IN关键字前边加上not可以将条件反过来

    语法:

    select …from …where c in(查询语句)
    --等价于:
    select ...from ... where c = result1 or c = result2 or c = result3
    

    案例:

    -- 查询指定部门的员工信息
    select eid,ename from emp where dept_id in (select deptno from dept where name = '研发部' or name = '销售部');
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bkLfgmXT-1689301955864)(C:\Users\FOVACE\AppData\Roaming\Typora\typora-user-images\image-20230714101331983.png)]

  • EXISTS关键字

    该子查询如果”有数据结果”(至少返回一行数据), 则该EXISTS() 的结果为“true”,外层查询执行;该子查询如果“没有数据结果”(没有任何数据返回),则该EXISTS()的结果为“false”,外层查询不执行;EXISTS后面的子查询不返回任何实际数据,只返回真或假,当返回真时 where条件成立。

    注意,EXISTS关键字,比IN关键字的运算效率高,因此,在实际开发中,特别是大数据量时,推荐使用EXISTS关键字

3、自关联查询

​ MySQL有时在信息查询时需要进行对表自身进行关联查询,即一张表自己和自己关联,一张表当成多张表来用。注意自关联时表必须给表起别名。

语法:

select 字段列表 from 表1 a , 表1 b where 条件;
或者 
select 字段列表 from 表1 a [left] join 表1 b on 条件;

案例:

– 数据准备

create table t_sanguo(
    eid int primary key ,
    ename varchar(20),
    manager_id int,
 foreign key (manager_id) references t_sanguo (eid)  -- 添加自关联约束
);

insert into t_sanguo values(1,'刘协',NULL);
insert into t_sanguo values(2,'刘备',1);
insert into t_sanguo values(3,'关羽',2);
insert into t_sanguo values(4,'张飞',2);
insert into t_sanguo values(5,'曹操',1);
insert into t_sanguo values(6,'许褚',5);
insert into t_sanguo values(7,'典韦',5);
insert into t_sanguo values(8,'孙权',1);
insert into t_sanguo values(9,'周瑜',8);
insert into t_sanguo values(10,'鲁肃',8);

-- 查询每个三国人物及他的上级信息,如:  关羽  刘备 
select * from t_sanguo a, t_sanguo b where a.manager_id = b.eid;

你可能感兴趣的:(mysql,数据库,navicat,多表查询,连接查询,约束)