MySQL---数据库从入门走向大神系列(四)-子查询、表与表之间的关系

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 本篇博客讲解(子查询)非相关子查询/相关子查询,一对一,一对多,多对一,多对的的关系!准备:首先我们创建一列sex。再为部分行设置好值0(女)或者1(男);delete from stud where age=26; 删除年龄为26的行。

本篇博客讲解(子查询)非相关子查询/相关子查询,一对一,一对多,多对一,多对的的关系!

准备:

首先我们创建一列sex。再为部分行设置好值0(女)或者1(男);

delete from stud where age=26;
删除年龄为26的行。

 update stud set sex='1' where saddress like '湖南%';

将地址中湖南开头的人的的sex修改为1。

update stud set sex='0' where age>=30 and sex is null;

将年龄大于等于30的,且性别为null的人的sex设置为0.

case-when then else end 语句.

现在要做这样一件事,查询显示的时候sex不显示0,1和null,我们让它0的就显示女,1的就显示男,null就显示未知。
这时我们需要用到:
case-when then else end 语句.

修改 * 当 * 时候 修改成 * 否则修改成 * END
when then 可以写多句

select sno,sname,age,saddress,(case sex when '0' then '女' when '1' then '男' else '未知' end) as 性别 from stud;

有人可能会有疑问,不是定义了sex只能有一个字符嘛,为什么还能用‘未知’啊,因为这里只是显示的,并不是存储到数据库中的数据,只是相当于输出字符。

子查询:

子查询:嵌套在其它查询中的查询语句。(又称为内部查询)

主查询:包含其它子查询的查询称为主查询。(又称外部查询)

非相关子查询:

在主查询中,子查询只需要执行一次,子查询结果不再变化,供主查询使用,这种查询方式称为非相关子查询。
也可以这么理解:
非相关子查询是独立于外部查询的子查询,子查询总共执行一次,执行完毕后将值传递给外部查询。

现在我们来对这个表做一个查询:
查询具有年龄相同的人在2人及以上的,他们的年龄分别是多少。

select age from stud group by age having count(age)>=2;

count(age)在这里只是作为供主查询使用的条件。

相关子查询:

相关子查询的执行依赖于外部查询的数据,外部查询执行一行,子查询就执行一次。
也可以这么理解:
执行查询的时候先取得外部查询的一个属性值,然后执行与此属性值相关的子查询,执行完毕后再取得外部父查询的下一个值,依次再来重复执行子查询;

我们先把表格增加一列sex并设置好值。

接下来:
查询不但具有年龄相同的人在2人及以上的,而且性别是1的那些人的年龄。

SELECT age,sex FROM stud GROUP BY age,sex HAVING COUNT(age)>=2 AND sex='1';

表与表之间的关系:

一对一:

需要两个表。当然做项目时为了省空间,通常只建一个表,如果要实现一对一的查询,可以建立两个视图。示例如下:
1)先建物理表,初始化数据、

create table person(
    id int,
    name varchar(10),
    sex char(1),
    wife int,
    husband int
);
insert into person values(1,'小花','0',1,3);
insert into person values(2,'玉芳','0',0,4);
insert into person values(3,'张三','1',1,0);
insert into person values(4,'李四','1',2,0);
insert into person values(5,'王五','1',0,0);

2)建立两个视图

create view women as select * from person where sex='0';
create view men as select * from person where sex='1';

3)查询夫妻信息
92年以前是这样查询的:

select women.name as 妻子,men.name as 丈夫 from women,men where women.husband=men.id and women.id=men.wife;

一对多/多对一:

数据库设计分析:
案例:一个人可以拥有多辆汽车,要求查询出某人所拥有的所有汽车。

方案一:(差的设计-用一张表存储–数据冗余太严重)

编号   姓名  性别   年龄   汽车编号   车型  排量  价格
P001  Jack   男     25     C001     BMW    12L   80w
P001  Jack   男     25     C002     Benz   12L   100w
P001  Jack   男     25     C003     Benz   12L   100w
P002  Tom    男     25     C004     BMW    12L   80w
P002  Tom    男     25     C005     Benz   12L   100w
P003  Rose   女     25     C006     Benz   12L   100w

方案二(好的设计):
1)把一方单独建个表

编号   姓名  性别   年龄
P001  Jack   男     25
P002  Tom    男     25
P003  Rose   女     25

2)把多方也建个表(依赖一方,通过外键–补一个字段)
外键:位于依赖一方,它是被依赖一方是主键

汽车编号   车型  排量  价格    车主
 C001     BMW    12L   80w    P001
 C002     Benz   12L   100w   P001
 C003     Benz   12L   120w   P001
 C004     BMW    12L   80w    P002
 C005     Benz   12L   100w   P002
 C006     Benz   12L   100w   P003

3)代码实现:

create table person2(
    id varchar(32) primary key,
    sname varchar(30),
    sex char(1),
    age int
);
insert into person2 values('P1001','Jack','0',25);
insert into person2 values('P1002','Tom','1',22);
insert into person2 values('P1003','Rose','1',24);
insert into person2 values('P1004','张三','0',25);

create table car(
    id varchar(32) primary key,
    sname varchar(30),
    price numeric(10,2),
    /*numeric(a,b),a表示一共多少位数,b表示带有几位小数*/
    pid varchar(32),
    /*为字段pid定义一个外键约束(来自person2表的字段id)*/
    constraint car_fk foreign key(pid) references person2(id)
);

insert into car values('C001','BMW',80.5,'P1001');
insert into car values('C002','Benz',100,'P1001');
insert into car values('C003','BMW',120.05,'P1001');
insert into car values('C004','Benz',88.5,'P1002');
insert into car values('C005','QQ',8.5,'P1002');
insert into car values('C006','BIKE',0.5,'P1003');

查询每个人拥有的车辆:
92年之前的写法:

select person2.sname as 车主,car.sname as 车辆 from person2,car where car.pid=person2.id;

现在的内关联写法:

select person2.sname as 车主 ,car.sname as 车辆 from person2 join car on car.pid=person2.id;

一对多和多对一是一样的!反过来理解就是了。

多对多:

数据库设计分析
案例:一个人可以选择多门课程,一门课程又可以被多人选择。

方案一:(差的设计–数据冗余太严重)
1)学生表

编号   姓名  性别   年龄  电话 ...
P001  Jack   男     25
P002  Tom    男     25
P003  Rose   女     25

2)课程表

编号   名称   教材  学分...  学生
S001   Java   ...  ......   P001
S001   Java   ...  ......   P002
S001   Java   ...  ......   ...
S002   数据库  ... ......   P001
S002   数据库  ... ......   P002

pass。

方案二(好的设计:两个实体表+一个关系表):
1)学生表(独立)—实体

编号   姓名  性别   年龄  电话 ...
P001  Jack   男     25
P002  Tom    男     25
P003  Rose   女     25

2)课程表(独立)—实体

编号   名称   教材  学分... 
S001   Java   ...  ......
S002   数据库  ... ......
S003   XML   ... ......

3)选课表(专为体现多对多的关系而新增的表)–关系

课程编号  学生编号
S001      P001
S001      P002
...
S002      P002
S002      P003
...
S003      P001
...
--------------
外键      外键
 |         |
 |         |
  ---------
      |
   联合主键

4) 代码实现

create table stud(
    id varchar(32) primary key,
    sname varchar(30),
    age int
);
create table ject(
    id varchar(32) primary key,
    sname varchar(30)
);
create table sj(
    studid varchar(32),
    jectid varchar(32)
);
/*单独添加约束,必须先添加联合主键,再添加外键*/
/*创建联合主键*/
alter table sj add constraint pk_sj primary key(studid,jectid);
/*创建两个外键*/
alter table sj add constraint fk_stud foreign key(studid) references stud(id);
alter table sj add constraint fk_ject foreign key(jectid) references ject(id);

如果需要删除外键

alter table sj drop foreign key fk_stud;
alter table sj drop foreign key fk_ject;

初始化stud表数据

insert into stud values('P001','小花',25);
insert into stud values('P002','Jack',23);
insert into stud values('P003','Tom',24);
insert into stud values('P004','张三',24);
insert into stud values('P005','赵子龙',26);

初始化ject表:

insert into ject values('S001','Java');
insert into ject values('S002','JavaEE');
insert into ject values('S003','XML');
insert into ject values('S004','数据库');
insert into ject values('S005','JQuery');

初始化sj表:

insert into sj values('P001','S001');
insert into sj values('P001','S003');
insert into sj values('P002','S001');
insert into sj values('P002','S002');
insert into sj values('P002','S003');
insert into sj values('P003','S001');
insert into sj values('P004','S002');
insert into sj values('P004','S003');

关联(也称为连接):
左关联(left join) 右关联(right join) 内关联(inner join)
mysql不支持: 全关联(full join) 外关联(outter join)

可以把关联理解成:几个表合成一个新的表,然后在新表中进行查询!

查询哪些人选了哪些课:

92年之前是这样查询的:(没有用关联)

select stud.sname,ject.sname from stud,sj,ject where stud.id=sj.studid and ject.id=sj.jectid;

用内关联来:

select stud.sname,ject.sname from
    stud inner join sj on stud.id=sj.studid
         inner join ject on ject.id=sj.jectid;

内关联可以这样来看,以中间的sj表为主表,来合另外2个表。

查询哪些人没有选课:

不用关联的写法:

select stud.sname from stud where stud.id not in(select studid from sj);

用左关联的写法:

select stud.sname from
    stud left join sj on stud.id=sj.studid
         left join ject on ject.id=sj.jectid
    where ject.sname is null;
/*下面这句也可以查询出*/
select stud.sname from
    stud left join sj on stud.id=sj.studid
         left join ject on ject.id=sj.jectid
    where ject.id is null;

左关联就是把左边的表作为主表,也就是说,stud必须是完整的,可以增加,但不能减少,再按照sj表的关系,来添加ject表的数据。

查询哪些课程没人选:

不用关联的写法:

select ject.sname from ject where ject.id not in(select jectid from sj);

用左关联的写法:

select ject.sname from
    ject left join sj on ject.id=sj.jectid
         left join stud on stud.id=sj.studid
    where stud.id is null;

最后的那里也可以用stud.sname is null来判断。
但要注意,需要原来的stud表中的那个属性定义了not null。
否则会出现bug。

用右关联写:

select ject.sname from
    stud right join sj on stud.id=sj.studid
         right join ject on ject.id=sj.jectid
    where stud.sname is null;

左关联和右关联实质上是差不多的。认真的看下上面的左关联和右关联就可以看出来了。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
9天前
|
SQL 关系型数据库 MySQL
【揭秘】MySQL binlog日志与GTID:如何让数据库备份恢复变得轻松简单?
【8月更文挑战第22天】MySQL的binlog日志记录数据变更,用于恢复、复制和点恢复;GTID为每笔事务分配唯一ID,简化复制和恢复流程。开启binlog和GTID后,可通过`mysqldump`进行逻辑备份,包含binlog位置信息,或用`xtrabackup`做物理备份。恢复时,使用`mysql`命令执行备份文件,或通过`innobackupex`恢复物理备份。GTID模式下的主从复制配置更简便。
47 2
|
4天前
|
弹性计算 关系型数据库 数据库
手把手带你从自建 MySQL 迁移到云数据库,一步就能脱胎换骨
阿里云瑶池数据库来开课啦!自建数据库迁移至云数据库 RDS原来只要一步操作就能搞定!点击阅读原文完成实验就可获得一本日历哦~
|
8天前
|
关系型数据库 MySQL 数据库
RDS MySQL灾备服务协同解决方案构建问题之数据库备份数据的云上云下迁移如何解决
RDS MySQL灾备服务协同解决方案构建问题之数据库备份数据的云上云下迁移如何解决
|
5天前
|
人工智能 小程序 关系型数据库
【MySQL】黑悟空都掌握的技能,数据库隔离级别全攻略
本文以热门游戏《黑神话:悟空》为契机,深入浅出地解析了数据库事务的四种隔离级别:读未提交、读已提交、可重复读和串行化。通过具体示例,展示了不同隔离级别下的事务行为差异及可能遇到的问题,如脏读、不可重复读和幻读等。此外,还介绍了在MySQL中设置隔离级别的方法,包括全局和会话级别的调整,并通过实操演示了各隔离级别下的具体效果。本文旨在帮助开发者更好地理解和运用事务隔离级别,以提升数据库应用的一致性和性能。
51 2
【MySQL】黑悟空都掌握的技能,数据库隔离级别全攻略
|
7天前
|
SQL 关系型数据库 MySQL
【MySQL 慢查询秘籍】慢SQL无处遁形!实战指南:一步步教你揪出数据库性能杀手!
【8月更文挑战第24天】本文以教程形式深入探讨了MySQL慢SQL查询的分析与优化方法。首先介绍了如何配置MySQL以记录执行时间过长的SQL语句。接着,利用内置工具`mysqlslowlog`及第三方工具`pt-query-digest`对慢查询日志进行了详细分析。通过一个具体示例展示了可能导致性能瓶颈的查询,并提出了相应的优化策略,包括添加索引、缩小查询范围、使用`EXPLAIN`分析执行计划等。掌握这些技巧对于提升MySQL数据库性能具有重要意义。
34 1
|
9天前
|
关系型数据库 MySQL Linux
在Linux中,如何配置数据库服务器(如MySQL或PostgreSQL)?
在Linux中,如何配置数据库服务器(如MySQL或PostgreSQL)?
|
3天前
|
关系型数据库 MySQL 机器人
Django入门到放弃之数据库配置
Django入门到放弃之数据库配置
|
8天前
|
存储 NoSQL Java
MPP数据库入门介绍及集群部署
MPP数据库入门介绍及集群部署
23 0
|
10天前
|
数据可视化 关系型数据库 MySQL
Mysql8 如何在 Window11系统下完成跳过密钥校验、完成数据库密码的修改?
这篇文章介绍了如何在Windows 11系统下跳过MySQL 8的密钥校验,并通过命令行修改root用户的密码。
Mysql8 如何在 Window11系统下完成跳过密钥校验、完成数据库密码的修改?
|
12天前
|
SQL 存储 关系型数据库
数据库-MySQL-01(一)
数据库-MySQL-01(一)
16 4

热门文章

最新文章

下一篇
云函数