MySQL中的增删改查2

注:此博文为本人学习过程中的笔记

1.数据库约束

1.1.约束类型

not null - 指示某列不能存储 null 值

unique - 保证某列的每行必须有唯一的值

default - 规定没有给列赋值时的默认值

primary key - not null 和 unique 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录

foreign key - 保证一个表中的数据匹配另一个表中的值的参照完整性

check - 保证列中的值符合特定条件。对于MySQL数据库,对check进行分析,但忽略check子句

1.2.not null约束

-- 重新设置学生表结构
drop table if exists student;
create table student(
    id int not null,
    sn int,
    name varchar(20),
    qq_mail varchar(20)
);

1.3.unique:唯一约束 

指定sn列为唯一的,不重复的:

-- 重新设置学生表结构
drop table if exists student;
create table student(
    id int not null,
    sn int unique,
    name varchar(20),
    qq_mail varchar(20)
);

1.4.default:默认值约束 

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

-- 重新设置学生表结构
drop table if exists student;
create table student(
    id int not null,
    sn int unique,
    name varchar(20) default 'unknow',
    qq_mail varchar(20)
);

1.5.主键约束 

指定id列为主键

-- 重新设置学生表结构
drop table if exists student;
create table student(
    id int not null primary key,
    sn int unique,
    name varchar(20) default 'unknow',
    qq_mail varchar(20)
);

对于整数类型的主键,常搭配自增长auto_increment来使用,插入数据对应字段不给值时,使用最大值+1,注意当我们插入数据失败时,自增的主键仍会+1,所以我们之后成功插入的数据可能是有跳跃的

-- 主键是not null和unique的结合,可以不用not null
id not primary key auto_increment,

1.6.foreign key:外键约束 

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

foreign key (字段名) references 主表(列)

案例:

创建班级表classes,id为主键

-- 创建班级表,有使用MySQL关键字作为字段时,需要使用``来标识
drop table if exists classes;
create table classes(
    id int primary key auto_increment,
    name varchar(20),
    `desc` varchar(100)
);

创建学生表student,一个学生对应一个班级,一个班级对应多个学生,使用id为主键,classes_id为外键,关联班级表id

-- 重新设置学生表结构
drop table if exists student;
create table student(
    id int primary key auto_increment,
    sn int unique,
    name varchar(20) default 'unknow',
    qq_mail varchar(20),
    classes_id int,
    foreign key (classes_id) referencecs classes(id)
); 

1.7.check约束(了解) 

MySQL使用时不报错,但忽略该约束

drop table if exists test_user;
create table test_user(
    id int,
    name varchar(20),
    sex varchar(1),
    check (sex = '男' or sex = '女')
);

2.表的设计 

2.1.三大范式 

设计表的时候一般遵循三大范式,不过在实际生产中会根据需求来设计表,并不一定严格遵守

2.1.1.第一范式 

·第一范式是关系型数据库的一个最基本的要求,不满足第一范式就不可以称为关系型数据库

·第一范式是指表里的字段不可再拆分(由于MySQL本身就是关系型数据库,所以MySQL里不存在能拆分的基本数据类型)

·在定义表的时候,对照到数据库中的数据类型

·每一个字段都可以用一个数据类型表示,那么当前这个表就天然满足第一范式 

2.1.2.第二范式 

·在满足第一范式的基本上,不存在非关键字段对任意候选键的部分函数依赖(存在于复合主键的情况下)

·名词解析:

非关键字段:可以理解为非主键字段

候选键:可以理解为主键,外键,没有主键时的唯一键

复合主键:一个表中不能存在多个主键,但是一个主键中可以包含多个列[primary key(列, 列)]

·当一个表中没有复合主键时,这个表天然满足第二范式

·当一个表中存在一些关键字依赖复合主键的一个部分,另一些关键字依赖复合主键的另一个部分,就说存在部分函数依赖

不满足第二范式可能会出现的问题 

1.数据冗余

2.更新异常

3.插入异常

4.删除异常 

2.1.3.第三范式

在第二范式的基础上,不存在非关键字字段,对任一候选键的传递依赖

2.2.设计表的三种关系 

一对一

一对多

多对一

3.新增 

插入查询结果

语法:

INSERT INTO table_name [column, column] SELELCT ...

案例:创建一张用户表,设计有name,email,sex,mobile。需要把已有的学生数据复制进来,可以复制的字段为name,qq_mail 

-- 创建用户表
drop table if exists test_user;
create table test_user(
    id int primary key auto_increment.
    name varchar(20),
    age int,
    email varchar(20),
    sex varchar(1),
    mobile varchar(20)
);

-- 将学生表的所有数据赋值到用户表
insert into test_user(name, email) select name, qq_mail from student;

4.查询

4.1.聚合查询 

4.1.1.聚合函数 

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

count()        返回查询到的数据的数量

sum()        返回查询的数据的总和,不是数字没有意义

avg()        返回查询到的数据的平均值,不是数字没有意义 

max()        返回查询到的数据的最大值,不是数字没有意义

min()        返回查询到的数据的最小值,不是数字没有意义 

案例:

count
-- 统计班级总共有多少同学
select count(*) from student;
select count(0) from student;

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

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

4.1.2.group by子句 

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

select column1, sum(column2), ... from table group by column1, column3;

案例:职员表 

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);

查询每个角色的最高工资,最低工资和平均工资

select role, max(salary), min(salary), avg(salary) from emp group by role;

4.1.3.having 

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

显示平均工资低于1500的角色和它的平均工资

select role, max(salary), min(salary), avg(salary) from emp group by role 
    having avg(salary) < 1500;

注:where 和 having 是可以混用的

4.2.联合查询 

实际开发中往往数据来自不同的表,所以需要多表联合查询。多表查询是对多张表的数据取自笛卡尔积。(笛卡尔积就是几个表中的数据进行全排列)

4.2.1联合查询的步骤 

1.首先确定哪几张表要参与查询

2.根据表与表之间的主外键关系确定过滤条件

3.精简查询字段,得到想要的结果 

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

案例:先初始化测试数据

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.2.内连接 

语法:

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

案例:

1.查询“许仙”同学的成绩

select sco.score from student stu 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.查询所有同学的总成绩,及同学的个人信息

-- 成绩表对学生表是多对一关系,查询总成绩是根据成绩表的同学id进行分组的
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.查询所有同学的成绩,及同学的个人信息

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

-- 学生表,成绩表,课程表3张表关联查询
select 
    stu.id,
    stu.sn,
    stu.qq_mail,
    sco.score,
    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
group by 
    stu.id;

4.2.3.外连接 

外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接,右侧的表完全显示就是右外连接 

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

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

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

4.2.4.自连接

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

案例:

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

-- 先查询“计算机原理”和“Java”课程的id
select id.name form 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;

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

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语句,也叫嵌套查询

单行子查询:

返回一行记录的子查询

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

select * from student where class_id = (select classes_id from student where name = '不想毕业');
多行子查询:

返回多行记录的子查询

案例:查询“语文”或“英语”的成绩信息 

-- 使用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 != '英文');
在from子句中使用子查询

子查询语句出现在from子句中,这里要用到数据查询的技巧,把一个子查询当作一个临时表使用

案例:查询所有比“中文系2019级3班”平均分高的成绩信息

-- 获取"中文系2019级3班的平均分,将其看作临时表"
select 
    avg(sco.score) score
    join student stu on sco.student_id = stu.id
    join classes cls on stu.classes_id = cls.id
where
    cls.name = '中文系2019级3班';

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

select 
    *
from
    score sco,
    (
    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班'
    )tmp
where
    sco.score > tmp.score;

4.2.6.合并查询

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

union 

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

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

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"的课程

-- 可以看到结果集中重复数据Java
select * from course where id < 3
union all
select * from course where name = '英文';

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值