MySQL增删改进阶

目录

1.数据库约束

1.1约束类型

[1.2 not null约束](#1.2 not null约束)

[1.3 unique:唯一约束](#1.3 unique:唯一约束)

[1.4 default:默认约束](#1.4 default:默认约束)

[1.5 primary key:主键约束](#1.5 primary key:主键约束)

[1.6 foreign key:外键约束](#1.6 foreign key:外键约束)

[1.7 check约束(了解)](#1.7 check约束(了解))

2.表的设计

3.新增(进阶)

4.查询

[4.1 聚合查询](#4.1 聚合查询)

[4.1.1 聚合函数](#4.1.1 聚合函数)

[4.1.2 group by 子句](#4.1.2 group by 子句)

[4.1.3 having](#4.1.3 having)

子句使用顺序

[4.2 联合查询](#4.2 联合查询)

4.2.1内连接

[4.2.2 外连接](#4.2.2 外连接)

[4.2.3 全外连接](#4.2.3 全外连接)

[4.2.4 自连接](#4.2.4 自连接)

[4.2.5 子查询](#4.2.5 子查询)

4.2.5合并查询

5.内容总结

关键字执行顺序:


本篇博客的目标:

  • 数据库约束关系
  • 表的关系
  • 新增
  • 删除
  • 修改
  • 查询

1.数据库约束

1.1约束类型

  • not null -指示某列不能存储null值
  • unique-保证某列的每行必须有唯一的值
  • default-规定没有给列赋值时的默认值
  • primary key-not null和unique的结合。确保某列(或多个列的结合)有唯一标识,有助于更容易快速地找到表中的一个特定的记录。
  • foreign key-保证一个表中的数据匹配另一个表中的值的参照完整性。
  • check-保证列中的值符合指定的条件。对于mysql数据库,对check子句进行分析,但是忽略check子句。

1.2 not null约束

创建表时,可以指定某列不为空:

sql 复制代码
-- 设置学生表结构
create table student(
    id int not null,
    sn int,
    name varchar(20),
    qq_mail varchar(20)
);

1.3 unique:唯一约束

指定sn列唯一、不重复的:

sql 复制代码
create table student(
    id int not null,
    sn int unique,
    name varchar(20),
    qq_main varchar(20)
);

了解:unique约束,会让后续插入/修改数据的时候都先触发一次查询操作,通过这个查询,来确定当前的记录是否存在,即通过引入unique后执行效率会受到影响,就可能降低很多。

1.4 default:默认约束

指定插入数据时,name列为空,默认值unkown:

sql 复制代码
create table student(
    id int not null,
    sn int unique,
    name varchar(20) default 'unknow',
    qq_mail varchar(20)
);

1.5 primary key:主键约束

指定id为主键:

sql 复制代码
create table student(
    id int not null primary key,
    sn int unique,
    name varchar(20) default 'unkown',
    qq_main varchar(20)
);

主建的特点:具有唯一性;不允许为空。

++注意:一个表只能有一个主键(某些情况下可能会看到一个表用多个字段作为主键,即联合主键,这种方式本质上是将多个字段作为一个整体来作为一个主键来使用),但可以有多个唯一键;++

++主键可以作为外键,但是唯一键不可以(唯一键可能为空)。++

对于整数类型的主键,常搭配自增长++auto_increment++来使用。插入数据对应字段不给值时,使用最大值+1。

eg.

sql 复制代码
-- 主键not null 和unique的结合,可以不用not null
id int primary key auto_increment,

1.6 foreign key:外键约束

外键用于关联其他表的主键或唯一键,语法:

sql 复制代码
foreign key (字段名) reference 主表(列)

案例:

  • 创建班级表classes,id作为主键:
sql 复制代码
create table classes(
    id int primary key auto_increment,
    name varchar(20),
    `desc` varchar(100)   
);

-- 有使用mysql关键字作为字段时,需要使用` ` 反引号或" "来标识
  • 创建学生表student,一个学生对应一个班级,一个班级对应多个学生。使用id为主键,classes_id为外键,关联班级表id
sql 复制代码
create table student(
    id int primary key auto_increment,
    sn int unique,
    name varchar(20) default 'unknown',
    qq_mail varchar(20),
    classes_id int,
    foreign key (classes_id) references classes(id)
);

注意:

  • ++一般使用父表的主键(主键或是唯一键)作为子表的外键。++
  • ++插入数据时,必须插入父表,然后才能插入子表。++
  • ++删除表时,必须先删除子表再删除父表。++

1.7 check约束(了解)

在实际开发中,可能会遇到这样一个场景,有一个age列,我们需要限制它的值为0~200,这样是为了防止输入的年龄值超过正常的范围。在mysql中我们可以使用check属性来为某一列添加条件检查。

语法:

sql 复制代码
列名 数据类型 check(表达式)

eg.

sql 复制代码
create table products(
    id int,
    name varchar(10),
    type varchar(10),
    city varchar(10) check(city in('广州','杭州')),
    price decimal(5,1),
    rdate date
);

city列中约束为check,该列的取值只能是"广州","杭州"。


2.表的设计

根据需求场景,明确实体,从而明确创建多少个表,此外,这些表中之间存在一定的联系。

实体可以认为是对象, 一般来说每个实体需要安排一个表,而表的列就对应实体的属性。

一对一:

一对多:

多对多:

  • 创建课程表:
sql 复制代码
create table course(
    id int primary key auto_increment,
    name varchar(20)
);
  • 创建学生课程中间表,考试成绩表:
sql 复制代码
create table score(
    id int primary key auto_increment,
    score decimal(3,1),
    student_id int,
    course_id int,
    foreign key (student_id) references student(id),
    foreign key (course_id) references course(id)
);

3.新增(进阶)

插入查询结果:

sql 复制代码
insert into table_name [column]  select...

案例:创建一张用户表,设计name姓名,email邮箱,sex性别,mobile手机号字段。需要把已有的学生数据复制进来,可以复制字段name。qq_emial

eg.

sql 复制代码
create table test_uesr(
    id int primary key auto_increment,
    name varchar(20) comment '姓名',
    age int comment '年龄',
    email varchar(20) comment '邮箱',
    sex varchar(1) comment '性别',
    mobile varchar(20) comment '手机号'
);

-- 将学生表中的数据复制到用户表
insert into test_user(name,emial) select name,email from student;

4.查询

4.1 聚合查询

表达式查询是针对列和列之间的运算,聚合查询是在行和行之间的运算了。

4.1.1 聚合函数

常见的统计总数、计算平均值等操作,对行进行操作,可以使用聚合函数来实现,常见的聚合函数有:

案例:

  • count
sql 复制代码
-- 统计班级共有多少个同学
select count(*) from student;
select count(0) from student;

-- 统计班级收集的qq_mail 有多少个,qq_mail为null的数据不会计入结果
select count(qq_mail) from student;
  • sum
sql 复制代码
-- 统计数学成绩总分
select sum(math) from exam_result;

-- 不及格<60 的总分,没有结果,返回null
select sum(math) from exam_result where math<60;
  • avg
sql 复制代码
-- 统计平均分
select avg(chinese +math+english) 平均总分 from exam_result;
  • max
sql 复制代码
-- 返回英语最高分
select max(english) from exam_result;
  • min
sql 复制代码
-- 返回>70分以上的数学最高分
select min(math) from exam_result where math>70;

4.1.2 group by 子句

select 中使用group by子句可以对指定列进行分组查询。需要满足:使用group by进行分组查询时,++select指定的字段必须是"分组依据字段",字段中相同的为一组,其他字段若想出现在select中则必须包含在聚合函数中。++

语法:

sql 复制代码
select column,sum(column2),...from table group by column1,column3;

案例:

  • 准备测试表及数据:职员表,有id(主键),name(姓名),role(角色),salary(薪水)
sql 复制代码
create table emp(
    id int primary key auto_increment,
    name varchar(20) not null,
    role varchar(20) not null,
    salary numeric(11,2)
);

insert into emp(name,role,salary) values
('马云','服务员',1000.20),
('马化腾','游戏陪玩',2000.99),
('孙悟空','游戏角色',999.11),
('猪悟能','游戏角色',333.5),
('沙和尚','游戏角色',700.33),
('隔壁老王','董事长',12000.66);
  • 查询每个角色的最高工资,最低工资和平均工资
sql 复制代码
select role,max(salary),min(salary),avg(salary) from emp group by role;

++我们一说起group by子句,就应该把它和聚合函数结合起来。++

4.1.3 having

group by 子句进行分组后,需要对分组结果在进行条件过滤时,不能使用where语句,而需要使用having。

在进行查询的时候,要区分条件时分组之前的条件还是分组之后的条件。

eg.

1)查询每个岗位的平均工资,但是排除张三

sql 复制代码
select role,avg(salary) from emp where name!='张三' group by role;

2)查询每个岗位的平均薪资,但是排除平均薪资超过2w的结果。

sql 复制代码
select role,avg(salary) from emp group by having avg(salary)<20000;

注意:

having子句不能单独使用,而必须结合group by 子句一起使用。并且having子句必须写在group by子句之后。

子句使用顺序

顺序:

select-->from-->where-->group by-->having-->order by-->limit

4.2 联合查询

实际开发中往往数据来自不同的表,所以需要多联合查询。多表查询是对多张表的数据取笛卡尔积:

笛卡尔积是通过排列组合的方式得到的一个更大的表

笛卡尔积的列数,是这两个表的列数相加。

笛卡尔积的行数,是这两个表的行数相乘。

注意:关联查询可以对关联表使用别名。

初始化测试数据:

sql 复制代码
insert into classes(name,`desc`) values
('计算机系2019级1班','学习了计算机原理、C语言和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');

insert into student(sn,name,qq_mail,classes_id) values
('09982','黑旋风李逵','xuanfeng@qq.com',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','xuxian@qq.com',1),
('00054','不想毕业',null,1),
('51234','好好说话','say@qq.com',2),
('83223','tellme',null,2),
('09527','老外学中文','foreigner@qq.com',2);

insert into course(name) values
('java'),('中华传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');

insert into score(score, student_id, course_id) values
-- 黑旋风李逵
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
-- 菩提老祖
(60, 2, 1),(59.5, 2, 5),
-- 白素贞
(33, 3, 1),(68, 3, 3),(99, 3, 5),
-- 许仙
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
-- 不想毕业
(81, 5, 1),(37, 5, 5),
-- 好好说话
(56, 6, 2),(43, 6, 4),(79, 6, 6),
-- tellme
(80, 7, 2),(92, 7, 6);

4.2.1内连接

语法:

sql 复制代码
select 字段 from 表1 别名 [inner] join 表2 别名2 on 连接条件 and 其他条件;


select 字段 from 表1 别名,表2 别名2 where 连接条件 and 其他条件;

案例:

(1)查询'许仙'同学的成绩

sql 复制代码
select sco.score from student stu inner join score sco on stu.id 
=sco.student_id and stu.name='许仙';
-- 或者
select sco.score from student stu.score sco where stu.id =sco.
student_id and stu.name ='许仙';

(2) 查询所有同学的总成绩及同学的个人信息

sql 复制代码
select 
    stu.sn,
    stu.name,
    stu.qq_mail,
    sum(sco.score)
from 
    student stu
    join score sco on stu.id = sco.student_id
group by
    sco.student_id;

(3) ch查询所有同学的成绩,及同学的个人信息:

sql 复制代码
-- 查询出来的都是有成绩的同学,"老外学中文"同学没有显示
select *from student stu join score sco on stu.id =sco.student_id;

-- 学生表、成绩表。课程表3张表关联查询
select 
    stu.id,
    stu.sn,
    stu.name,
    stu.qq_mail,
    sco.score,
    sco.course,
    sco.course_id,
    cou.name
from
    student stu
    join score sco on stu.id = sco.student_id
    join course cou on sco.course_id = cou.id
order by
    stu.id;

4.2.2 外连接

外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接;如果这两个表的记录存在对应关系,内连接和外连接的结果是一致的,否则不一致。

语法:

sql 复制代码
-- 左外连接,表1完全显示
select 字段名 from 表名 left join  表名2 on 连接条件;

-- 右外连接,表2完全显示
select 字段 from 表1 right join 表名2 on 连接条件;

案例:查询所有同学的成绩及同学的个人信息,如果该同学没有成绩,也需要显示

sql 复制代码
-- 左连接
select *from student stu left join score sco on stu.id = sco.student_id;

-- 右连接
select *from score sco right join student stu on stu.id =sco.student_id;

-- 学生表、成绩表、课程表3张表关联查询
SELECT
 stu.id,
 stu.sn,
 stu.NAME,
 stu.qq_mail,
 sco.score,
 sco.course_id,
 cou.NAME
FROM
 student stu
 LEFT JOIN score sco ON stu.id = sco.student_id
 LEFT JOIN course cou ON sco.course_id = cou.id
ORDER BY
 stu.id;

4.2.3 全外连接

mysql并没有提供full outer join 这样的连接方式,如果想要在mysql中实现全外连接,我们可以稍微变通一下:首先获取左外连接的结果,然后在获取右外连接的结果,最后使用union求并集即可。

eg.

sql 复制代码
select *from staff left join market on staff.sid = market.sid
union
select *from staff right outer join market on staff.sid = market.sid;

图示了解这几个连接:

4.2.4 自连接

自连接是指在同一张表连接自身进行查询。

语法:

sql 复制代码
select 列名 
from 表名1 as 别名1,表名2 as 别名2;

案例:

显示所有"计算机原理"成绩比"Java"成绩高的成绩信息

sql 复制代码
-- 先查询"计算机原理"和"Java"课程的id
select id,name from course where name ='java' or name = '计算机原理';

-- 在查询成绩表中,"计算机原理"成绩比"Java"成绩好的信息
SELECT
 s1.* 
FROM
 score s1,
 score s2 
WHERE
 s1.student_id = s2.student_id
 AND s1.score < s2.score
 AND s1.course_id = 1
 AND s2.course_id = 3;

-- 也可以使用join on 语句来进行自连接查询
SELECT
 s1.* 
FROM
 score s1
 JOIN score s2 ON s1.student_id = s2.student_id
 AND s1.score < s2.score
 AND s1.course_id = 1
 AND s2.course_id = 3;

以上查询只显示了成绩信息,并且是分布式执行的。要显示学生及成绩信息,并在一条语句显示:

sql 复制代码
SELECT
 stu.*,
 s1.score Java,
 s2.score 计算机原理
FROM
 score s1
 JOIN score s2 ON s1.student_id = s2.student_id
 JOIN student stu ON s1.student_id = stu.id
 JOIN course c1 ON s1.course_id = c1.id
 JOIN course c2 ON s2.course_id = c2.id
 AND s1.score < s2.score
 AND c1.NAME = 'Java'
 AND c2.NAME = '计算机原理';

4.2.5 子查询

子查询时值嵌入在其他sql语句中的select语句,也叫嵌套查询。

  • 单行子查询:返回一行记录的子查询

查询与"不想毕业"同学的同班同学:

sql 复制代码
select *from student where classes_id =(select classes_id from student where
name = '不想毕业');
  • 多行子查询:返回多行记录的子查询

案例:查询"语文"或"英文课程"的成绩信息

1.[not] in 关键字:

sql 复制代码
-- 使用in
select*from score where course_id in (select id from course where name='语文' 
or name = '英文');

-- 使用not in
select *from score where course_id not in (select id from course where
name!='语文' and name!='英文');

2.[not] exists 关键字:

sql 复制代码
--使用 exists 
select *from score sco where exists  (select sco.id from course cou where (name ='语文'
 or  name ='英文') and cou.id =sco.course_id);

-- 使用not exists
select *from score sco where not exists (select sco.id from course cou where
(name!='语文' and name !='英文') and cou.id = sco.course_id);
sql 复制代码
-- 获取"中文系2019级3班"的平均分,将其看做临时表(参照表)
select 
    avg(sco.score) score
from 
    score sco
    join student stu on sco.student_id =stu.id
    join classes cls on stu.classes_id = cls.id
where
    cls.name ='中文系2019级3班';

查询成绩表中,比以上临时表平均分高的成绩:

sql 复制代码
-- 先得到平均分,然后在找比平均分高的成绩
select
    *
from
    score sco,
    (
    select 
        avg(sco.score) avg_score
    from
        score sco
        join student stu on sco.student_id = stu.id
        join classes cls on stu.classes_id = cls.id
    where 
        cls.name = '中文系2019级3班'
    ) tmp
where
    sco.score>tmp.avg_score;

4.2.5合并查询

在实际应用中,为了合并多个select的执行结果,可以使用集合操作符union,union all,使用union和union all时。前后查询的结果集中,字段个数和类型需要一致(列名不需要一致)。

  • union

该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。

案例:查询id小于3,或者名字为"英文"课程:

sql 复制代码
select *from course where id<3
union 
select *from course where name='英文';

-- 或者使用or来实现
select *from course where id<3 or name= '英文';
  • union all

该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。

案例:查询id小于3,或者名字为"Java"的课程

sql 复制代码
-- 可以看到结果集中出现重复数据Java
select *from course where id<3
union all
select *from course where name='java';

5.内容总结

  • 数据库约束
  • 表的关系
  1. 一对一:
  2. 一对多:
  3. 多对多:需要创建中间表来映射两张表的关系
  • 新增(进阶):
sql 复制代码
-- 将一个表的数据复制到另一个表中去
insert into table_name ([column1],[column2]....) select....
  • 查询

1.聚合函数:max,min,avg,count,sum

2.分组查询:group by....having....

3.内连接:

sql 复制代码
select....from 表1 ,表2 where 条件
-- inner可以缺省
select...from 表1 join 表2 on where 其他条件

4.外连接:

sql 复制代码
select...from 表1  left/right join 表2 on 条件 where 其他条件

5.自连接:

sql 复制代码
select ... from 表1,表1 where 条件
select ... from 表1 join 表1 on 条件

6.子查询:

sql 复制代码
-- 单行子查询
select...from 表1 where 字段1=(select...from...);

--[not] in
select..from 表1 where 字段1 in (select...from...);

-- [not] exists
select...from 表1 where exists(select...from...where 条件);

-- 临时表:from子句中的子查询
select...from 表1,(select..from...) as tmp where 条件

7.合并查询:

sql 复制代码
-- union 去除重复数据
select..from..where 条件
union
select..from..where 条件

-- union all 不去重
select..from...where 条件
union all 
select...from...where 条件

-- 使用union和union all 时,前后查询的结果集中,字段需要一致

关键字执行顺序:

SQL查询中各个关键字的执行先后顺序:from>on>join>where>group by>with>having>select>distinct>order by>limit

相关推荐
woshilys19 分钟前
sql server 查询对象的修改时间
运维·数据库·sqlserver
Hacker_LaoYi20 分钟前
SQL注入的那些面试题总结
数据库·sql
建投数据1 小时前
建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
数据库·腾讯云
Hacker_LaoYi2 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀2 小时前
Redis梳理
数据库·redis·缓存
独行soc2 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
你的微笑,乱了夏天3 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
工业甲酰苯胺3 小时前
分布式系统架构:服务容错
数据库·架构
独行soc4 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍08-基于时间延迟的SQL注入(Time-Based SQL Injection)
数据库·sql·安全·渗透测试·漏洞挖掘
White_Mountain4 小时前
在Ubuntu中配置mysql,并允许外部访问数据库
数据库·mysql·ubuntu