mysql数据库--外键,联合查询以及子查询

回顾:

连接查询:多张表连接到一起,不管记录数如何,字段数一定会增加。
	分类:内连接,外连接,自然连接和交叉连接。
	交叉连接:cross  join(笛卡尔积)
	内连接:inner  join,左右两张表中有连接条件匹配(不忽略的匹配)
	外连接:outer  [left/right]  join,主表有的记录一定会存在,匹配了就保留副表字段数据,没匹配就将副表字段置空。
	自然连接:natural  join,自动匹配条件(相同的字段名),using关键字可以将内外连接转换成自然连接。
PHP操作mysql:
	PHP充当客户端,开启mysql扩展
	连接认证:mysql_connect;发送SQL获取结果:mysql_query;解析结果集:mysql_fetch系列;释放资源:mysql_free_result
	和mysql_close;错误处理:mysql_ermo和mysql_error。

外键:

外键:foreign  key,外面的键(键不在自己的表中);如果一张表中有一个字段(非主键)指向另外一张表的主键,
那么将该字段叫为外键。一张表可以有多个外键。

增加外键:

外键可以在创建表的时候或者创建表之后增加(但是要考虑数据的问题)
1.在创建表的时候增加外键:在所有的字段之后,使用foreign  key(外键字段)  references  外部表
-- 创建外键 
create table my_foreign1(
id int primary key auto_increment,
name varchar(20) not null comment '学生姓名',
c_id int comment '班级ID',
-- 增加外键
foreign key(c_id) references my_class(id)
)charset utf8;

确保my_class表有主键:
在这里插入图片描述
在这里插入图片描述

在新增表之后增加外键:修改表结构
alter  table  表名  addconstraint  外键名字] foreign  key(外键字段)  references  父表(主键字段)
-- 创建表
create table my_foreign2(
id int primary key auto_increment,
name varchar(20) not null comment '学生姓名',
c_id int comment '班级ID'    -- 普通字段
)charset utf8;

-- 增加外键
alter table my_foreign2 add
-- 指定外键名
constraint student_class_1
-- 指定外键字段
foreign key(c_id)
-- 引用父表主键
references my_class(id);

在这里插入图片描述

修改外键&删除外键

外键不可以修改:只能先删除再新增
删除外键:alter  table  表名  drop  foreign  key  外键名;  -- 一张表中可以有多个外键,外键名字不可以相同
-- 删除外键
alter table my_foreign1 drop foreign key my_foreign_ibfk_1;

在这里插入图片描述

外键(默认约束)

外键默认的作用有两点:一个对父表,一个对子表(外键字段所在的表)
对子表的约束:子表数据进行写操作的时候,如果对应的外键字段在父表找不到对应的匹配,那么操作会失败(约束子表数据操作)
-- 插入数据:外键字段在父表中不存在
insert into my_foreign2 values(null,'xff',4);  --没有4班级

在这里插入图片描述

对父表约束:父表数据进行写操作(删和改:都必须涉及到主键本身),如果对应的主键在子表中已经被数据所引用,
那么就不允许操作。
insert into my_foreign2 values(null,'xfd',1);
insert into my_foreign2 values(null,'xfs',2);
insert into my_foreign2 values(null,'xff',2);

在这里插入图片描述

-- 更新父表记录
update my_class set id = 4 where id = 1;
update my_class set id = 4 where id = 3;

在这里插入图片描述

外键的条件:

1.外键要存在:首先要保证表的存储引擎是innodb(默认的存储引擎);如果不是innodb存储引擎,那么外键可以创建成功,
但是没有约束效果。
2.外键字段的字段类型(列类型)必须与父表的主键类型完全一致。
3.一张表中的外键名字不能重复。
4.增加外键的字段(数据已经存在),必须保证数据与父表主键对应。
-- 增加外键
alter table my_foreign1 add foreign key(c_id) references my_class(id); 

在这里插入图片描述

外键约束:

所谓外键约束:就是指外键的作用,之前所讲的外键的作用:是默认的作用,其实可以通过对外键的需求,进行定制操作。
外键约束有三种模式:都是针对父表的约束
	distinct:严格模式(默认的),父表不能删除或者更新一个已经被子表数据引用的记录。
	cascade:级联模式:父表的操作对应子表关联的数据也跟着操作。
	set  null:置空模式:父表操作之后,子表对应的数据(外键字段被置空)

通常的一个合理的约束模式:删除的时候子表置空,更新的时候子表级联操作。
指定模式的语法:foreign  key(外键字段)  references  父表(主键字段)  on  delete 模式  update  模式;
foreign  key(外键字段)  references  父表(主键字段)  on  delete set null  on  update  cascade;
-- 创建外键:指定模式:删除置空,更新级联
create table my_foreign3(
id int primary key auto_increment,
name varchar(20) not null,
c_id int,
-- 增加外键
foreign key(c_id)
-- 引用表
references my_class(id)
-- 指定删除模式
on delete set null
-- 指定更新模式
on update cascade
)charset utf8;

在这里插入图片描述
在这里插入图片描述

-- 插入数据
insert into my_foreign3 values(null,'刘备',1),
(null,'曹操',1),
(null,'孙权',1),
(null,'诸葛亮',2),
(null,'周瑜',2);

在这里插入图片描述
在这里插入图片描述

更新操作:级联更新

-- 更新父表主键
update my_class set id = 3 where id = 1;

在这里插入图片描述

删除操作:置空模式

-- 删除父表主键
delete from my_class where id = 2;

在这里插入图片描述

删除置空的前提条件:外键字段允许为空(如果不满足条件,外键无法创建),外键虽然很强大,能够进行各种约束,但是
对于PHP来讲,外键的约束降低了PHP对数据的可控性,在实际开发中很少使用外键来处理。

联合查询:

联合查询:将多次查询(多条select语句),在记录上进行拼接(字段不会增加)
基本语法:
多条select语句:每一条select语句获取的字段数必须严格一致(但是字段类型无所谓)
select  语句1  
Union  [union  选项]
select  语句2...

union选项与select选项一样有两个:All:保留所有(不管重复);distinct:去重(整个重复,默认的方式)
-- 联合查询
select * from my_class
union -- 默认去重
select * from my_class;

select * from my_class
union all -- 不去重
select * from my_class;

在这里插入图片描述

联合查询只要求字段一样,跟数据类型无关。

在这里插入图片描述

联合查询的意义:

1.查询同一张表的需求不同的信息:如查询学生信息,男生身高升序,女生身高降序。
2.多表查询:前提保证多张表的结构是完全一样的。

order by的使用

在联合查询中,order  by不能直接使用,需要对查询语句使用括号才行。

在这里插入图片描述

若要order  by生效,必须搭配limit,limit使用限定最大数即可。

在这里插入图片描述

子查询:

子查询:sub  query,查询是在某个查询结果之上进行的(一条select语句内部包含另外一条select语句)
子查询的分类:
按位置分类:子查询(select  语句)在外部查询(select  语句)中出现的位置。
	from子查询:子查询跟在from之后
	where子查询:子查询出现在where条件中
	exists子查询:子查询出现在exists中
按结果分类:根据子查询得到的数据进行分类(理论上讲任何一个查询得到的结果都可以理解为二维表)
	标量子查询:子查询得到的结果是一行一列
	列子查询:子查询得到的结果是一列多行
	行子查询:子查询得到的结果是多行一列(多行多列)
		上面几个子查询出现的位置都在where之后
	表子查询:子查询得到的结果是多行多列(出现的位置在from之后)

标量子查询:

需求:知道班级名字为PHP0710,想获取该班的所有学生。
-- 标量子查询
select * from my_student where c_id = (select id from my_class where c_name = 'php0710');
1.确定数据源,获取所有的学生:select  *  from  my_student  where  c_id = ?;
2.获取班级ID,可以通过班级名字确定:
select  id  from  my_class  where  c_name = 'php0710'; -- ID一定只有一个值(一行一列)

在这里插入图片描述

列子查询:

需求:查询所有在读班级的学生(班级表中存在的班级)
1.确定数据源:学生
select  *  from  my_student  where  c_id  in  (?);
2.确定有效班级的ID:所有班级ID
select  id  from  my_class;

搭建实验环境增加实验数据:
在这里插入图片描述

-- 列子查询
select * from my_student where c_id in (select id from my_class);

在这里插入图片描述

列子查询返回的结果会比较多:一列多行,需要使用in作为条件匹配,在mysql中还有很多类似的条件:all,some,any等
=any才会相当于in;any完全等价于some。any代表其中一个即可,all代表全部

肯定结果的查询演示:

-- 肯定结果演示
select * from my_student where c_id =any (select id from my_class);
select * from my_student where c_id =some (select id from my_class);
select * from my_student where c_id =all (select id from my_class);

在这里插入图片描述

否定结果的查询演示:

-- 否定结果演示
select * from my_student where c_id !=any (select id from my_class);  -- 所有结果(null除外)
select * from my_student where c_id !=some (select id from my_class);  -- 所有结果(null除外)
select * from my_student where c_id !=all (select id from my_class);  -- 只有2(null除外)

在这里插入图片描述

行子查询:

行子查询:返回的结果是多行多列(一行多列)
需求:要求查询整个学生中,年龄最大且身高最高的学生。
1.确定数据源
select  *  from  my_student  where  age = ?  and  height  =  ?;
2.确定最大的年龄和最高的身高
select  max(age),max(height)  from  my_student;
初步设想的子查询:
select * from my_student where 
age = (select max(age) from my_student)
and
height = (select max(height) from my_student);

在这里插入图片描述

行子查询:需要构造行元素,行元素有多个字段组成。
-- 行子查询
select * from my_student where
-- (age,height)称之为行元素
(age,height) = (select max(age),max(height) from my_student);

在这里插入图片描述

还有一种方式如下图所示:虽然查询出来的结果都是一样的,但是存在以下几个问题:
1.当年龄最高的和身高最高的不是一致的会出现数据表混乱。
2.如果有多个字段同时满足情况这样查询很明显具有局限性。

在这里插入图片描述

表子查询:

表子查询:子查询返回的结果是多行多列的二维表,子查询返回的结果当作二维表来使用。
需求:要求找出每个班最高的一个学生。
1.确定数据源:先将学生按照身高进行降序排序
select  *  from  my_student  order  by  height  desc;
2.从每个班选出第一个学生
select  *  from  my_student  group  by  c_id;  -- 每个班选出第一个学生

表子查询:from子查询。得到的结果作为from的数据源
select * from (select * from my_student order by height desc) as student group by c_id; 

效果展示:
在这里插入图片描述

exists子查询:

exists:是存在的意思,exists子查询就是用来判断某些条件是否满足(跨表),exists是接在where之后,返回的结果只有0和1.

在这里插入图片描述

需求:查询所有学生,前提是班级存在。
1.确定数据源
select  *  from  my_student  where  ?;
2.确定条件是否满足
exists(select  *  from  my_class);   -- 是否成立
-- exists子查询
select * from my_student where
exists(select * from my_class);
-- 班级ID存在
select * from my_student where
exists(select * from my_class where id = 1);
-- 班级ID不存在
select * from my_student where
exists(select * from my_class where id = 2);

在这里插入图片描述

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值