0


MySQL表的增删改查(进阶)

数据库约束

约束的定义

定义:创建表时,给这个表制定一些规则,后续插入/修改/删除都要保证数据能够遵守这些规则.

引入约束的规则,是为了更强的数据检查/校验.数据一定要保证正确性.(如果后续插入/修改的数据不符合要求,就会报错)

执行效率(代码在机器上跑的快不快)

开发效率(程序员写代码所花费的时间)

*我们讲***约束也是牺牲了执行效率,换来了开发效率.**因为开发效率更重要:因为人力成本高于机器硬件成本.

约束类型

共分为not null, unique, default, primary key, check这几种

null约束

定义:指示某列不能存储null值

在创建表时,就是指定某列不为空,当指定列插入null会报错

-- 重新设置学生表结构

DROP TABLE IF EXISTS student;

CREATE TABLE student (

id INT NOT NULL,

sn INT,

name VARCHAR(20),

qq_mail VARCHAR(20)

);

unique:唯一约束

定义:保证某列的每行必须有唯一的值.

指定sn为唯一的,不重复的(即在这一列都不会出现):

-- 重新设置学生表结构

DROP TABLE IF EXISTS student;

CREATE TABLE student (

id INT NOT NULL,

sn INT UNIQUE,

name VARCHAR(20),

qq_mail VARCHAR(20)

);

default:默认值约束

定义:规定没有给列赋值时赋默认值.(默认情况下的默认值设置为null)

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

-- 重新设置学生表结构

DROP TABLE IF EXISTS student;

CREATE TABLE student (

id INT NOT NULL,

sn INT UNIQUE,

name VARCHAR(20) DEFAULT 'unkown',

qq_mail VARCHAR(20)

);

primary key:主键约束(重要)

定义:not null和unique的结合.确保某列(或两个列,多个列的组合)有唯一标识(就是一个记录的身份标识),有助于更容易更快速地找到表中的一个特定记录.(通常用xxx id作为主键,通常一个表中只有一个主键).

指定id列为主键:

-- 重新设置学生表结构

DROP TABLE IF EXISTS student;

CREATE TABLE student (

id INT NOT NULL PRIMARY KEY,

sn INT UNIQUE,

name VARCHAR(20) DEFAULT 'unkown',

qq_mail VARCHAR(20)

);

自增主键的介绍:auto_increment(对id(主键)的+1操作)

不需要用户自己指定(可以放个null),可交给数据库进行分配(1,2,3...)

其实,程序员可以自行设定id亦可

每次使用null方式插入自增主键时,都是数据库根据这一列的最大值,在这个基础上,继续递增,不会重复利用之前上述的自增主键,只能在当前单个数据库下生效

如果数据库是由多个mysql服务器构成集群时,自增主键就无效了

在实际业务当中,引入的主键是不希望重复的.

id INT PRTMARY KEY auto_increment,

foreign key:外键约束(描述两个表之间的关联)

定义:保证一个表中的数据匹配另一个表中的值的参照完整性.

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

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

-- 字段名是指本表的哪个列

-- 主表是指被关联的表

-- 列就是被关联的表的哪个列

注:外键约束是写到最后,把前面的定义好之后,在最后通过foreign key创建外键约束.

案例:

创建班级表classes,id为主键:

-- 创建班级表,有使用MySQL关键字作为字段时,需要使用``来标识

DROP TABLE IF EXISTS classes;

CREATE TABLE classes (

    id INT PRIMARY KEY auto_increment, 

    name VARCHAR(20), 

    `desc` VARCHAR(100) 

);

设计要求:学生表中的class_id都在班级表中存在

创建学生表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 'unkown',

qq_mail VARCHAR(20),

classes_id int,

FOREIGN KEY (classes_id) REFERENCES classes(id)

);

1.把约束别的表的表称为"父表".

** 把被约束的表,称为"子表".**

2.外键约束,也是双向的,要想删除父表的记录,就必须先删除子表中的相关数据,以确保子表中没有数据.

3.使用外键约束时,操作子表,要查询父表;操作父表,也要查询子表.子表和父表中被引用的列都要带有"索引".表里有了主键之后,就会自动创建出索引,加快查询速度

4.扩展知识:对电脑上的文件进行删除,也只是逻辑上的删除,不是真的删除.把文件删除掉,其实也是在系统中,把硬盘对应的盘块数据标记为无效了(所以不是真正意义上的删除)

表的设计

一般思路

1.先根据需求,找到实体(一些关键性质的对象),梳理清需求,提取出关键字的名字,一般来说,每个实体,都得安排个表.

2.梳理实体间的关系(不同关系下,有不同设计表的方式),造句,向里面套,能套上哪个,就用哪种方式创建数据表(定式)

三大范式

一对一

方案一:搞一个大表,把这些信息都放在一起(前提是这两个表都很简单(即列很少,可以考虑合并))

方案二:分两个表,使用id引用过来,建立联系(可用于表很复杂的情况)

一对多

多对多

创建课程表

-- 创建课程表

DROP TABLE IF EXISTS course;

CREATE TABLE course (

id INT PRIMARY KEY auto_increment,

name VARCHAR(20)

);

创建学生课程中间表,考试成绩表

-- 创建课程学生中间表:考试成绩表

DROP TABLE IF EXISTS score;

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)

);

新增

插入查询结果

语法(将插入语句和查询语句结合到一起了):

**insert into table_name [(**column [, column...])] select ...

-- 查询结果的集合就代替了values

案例:创建一张用户表,设计有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) comment '姓名',

age INT comment '年龄',

email VARCHAR(20) comment '邮箱',

sex varchar(1) comment '性别',

mobile varchar(20) comment '手机号'

);

-- 将学生表中的所有数据复制到用户表

insert into test_user(name, email) select name, qq_mail from student;

查询

聚合查询

定义:就是"行和行"之间的运算,但此处行之间的运算具有一定限制,不像表达式查询(表达式查询是操作列).

聚合函数

使用聚合函数时,列和列之间,已经被"打散了",如果查询中包含聚合函数,和非聚合的列,各自是各自的.大部分情况,聚合的列和非聚合的列是不能混用的,一种情况除外(group by(后面讲))

函数****说明count([distinct] expr)返回查询到数据的数量sum([distinct] expr)返回查询到的数据的总和,不是数字则没有意义avg([distinct] expr)返回查询到数据的平均值,不是数字则没有意义max([distinct] expr)返回查询到数据的最大值,不是数字则没有意义min([distinct] expr)
返回查询到数据的最小值,不是数字则没有意义

案例:

count:

-- 统计班级共有多少同学

SELECT COUNT(*) FROM student;

SELECT COUNT(0) FROM student;

-- 统计班级收集的 qq_mail 有多少个,qq_mail 为 NULL 的数据不会计入结果

SELECT COUNT(qq_mail) FROM student;

注意:当使用count(*) 时,即使是全为null的行,也会被记录次数

    当使用count(列名)时,如果中间有为null的行,则不会被记录次数

sum:

-- 统计数学成绩总分

SELECT SUM(math) FROM exam_result;

-- 不及格 < 60 的总分,没有结果,返回 NULL

SELECT SUM(math) FROM exam_result WHERE math < 60;

注意:

1.sum函数会将null自动忽略

2.sql很多时候会将字符串当作数字进行算术运算,都会将字符串转为数字

(eg.允许"100"转换为100)

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;

group by字句

在select中使用group by可以对指定列进行分组查询.需要满足:使用group by进行分组查询时,select指定的字段必须是"分组依据字段", 其它字段如想出现在select中,必须包含在聚合函数中.

实际效果就是把这个指定的列,值相同的记录划分到一组,针对这些组就可以分别聚合查询了,分组操作,往往是和"聚合"配合使用的.

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

-- column1是分组依据

案例:

准备测试表及数据:职员表,有id(主键), name(姓名), role(角色), salary(薪水)

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;

having

group字句进行分组之后,需要对分组结果再进行条件过滤时,不能使用where语句,而需要用having语句.****(即分组之前的条件,使用where表示;分组之后的条件,使用having表示)

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

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

having avg(salary)<1500;

联合查询(也称多表查询)

所谓多表联合查询,核心操作为笛卡尔积,然后指定一些条件之类的,来实现需求中的一些查询结果.

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

笛卡尔积列数为之前列数之和,行数为两个表的行数之积.

但实际上,笛卡尔积得到的结果,绝大部分是无效数据.

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

让我们来看一下下面的案例(可以尝试自己敲一下):

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

注意:在进行多表查询时,始终贯穿着这四部曲(由繁入简),筛选出符合条件的数据:

1.笛卡尔积

2.连接条件

3.根据需求指定其他条件(筛选行)

4.针对列进行精简(筛选列)

内连接

定义:是内连接查询中一种特殊的等值连接,所谓的自连接就是指表与其自己当前表进行连接。自己和自己做连接。

语法:

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

select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;(个人最推荐第二种,嘎嘎好用)

案例:

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

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)查询所有同学的总成绩,以及同学的个人信息

-- 成绩表对学生表是多对1关系,查询总成绩是根据成绩表的同学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.NAME,

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

ORDER BY

    stu.id;

外连接

外连接分为左外连接和右外连接.如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接. 外连接也是多表查询的一种表现形式,一般使用比较少,属于特殊情况特殊处理.

语法:

-- 左外连接,表一完全显示

select 字段名 from 表名1 left join 表名2 on 连接条件;

-- 右外连接,表二完全显示

select 字段名 from 表名1 right join 表名2 on 连接条件;

为了形象展示内连接,左外连接和右外连接的区别,下面我们来看这一组图:

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

-- “老外学中文”同学 没有考试成绩,也显示出来了

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;

自连接

顾名思义,自连接就是指在同一张表中进行查询.

案例:

显示所有"计算机原理"成绩比"Java"成绩高的成绩信息(在这个例子中,要想完成不同科目的比较,就需要比较行之间的大小,因为sql是无法实现这个功能的,所以只能将行转为列)

-- 先查询“计算机原理”和“Java”课程的id

select id,name from course where name='Java' or name='计算机原理';

-- 让我们使用四部曲来写一下

(1)将所有内容进行笛卡尔积

select * from score as s1, score as s2;

(2)连接条件:两张表student_id相同

select * from score as s1, score as s2 where s1.student_id = s2.student_id;

(3)只筛选出要比较的课程id的数据

select * from score as s1, score as s2 where s1.student_id = s2.student_id and s1.course_id = 3 and s2.course_id = 1; 

(4)找出结果

select * from score as s1, score as s2 where s1.student_id = s2.student_id and s1.course_id = 3 and s2.course_id = 1 and s1.score > s2.score; 

子查询

子查询是指嵌入在其它sql语句中的select语句,也叫嵌套查询**(这个查询方法虽然很装逼但不建议用,所以了解这个即可,自己写的时候尽量不要这样写)**

举个例子:查询与"不想毕业"同班的同学:

select * from student where classes_id=(select classes_id from student where

name='不想毕业');

合并查询

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

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

select * from course where id<3

union

select * from course where name='英文';

-- 或者使用or来实现

select * from course where id<3 or name='英文';

标签: mysql 数据库

本文转载自: https://blog.csdn.net/asdssadddd/article/details/134318145
版权归原作者 灰灰快醒醒 所有, 如有侵权,请联系我们删除。

“MySQL表的增删改查(进阶)”的评论:

还没有评论