MySQL 约束&特殊查询

MySQL 约束&特殊查询

文章目录

  • [MySQL 约束&特殊查询](#MySQL 约束&特殊查询)
    • [1. 数据库约束](#1. 数据库约束)
      • [1.1 约束类型](#1.1 约束类型)
      • [1.2 NULL约束](#1.2 NULL约束)
      • [1.3 NUIQUE:唯一约束](#1.3 NUIQUE:唯一约束)
      • [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. 表的关系](#2. 表的关系)
      • [2.1 一对一](#2.1 一对一)
      • [2.2 一对多](#2.2 一对多)
      • [2.3 多对多](#2.3 多对多)
    • [3. 特殊新增](#3. 特殊新增)
    • [4. 查询](#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.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.6 合并查询](#4.2.6 合并查询)

1. 数据库约束

1.1 约束类型

NOT NULL: 指示某列不能存储NULL值

UNIQUE:保证某列的每行必须有唯一的值

DEFAULT:规定没有给列赋值时的默认值

PRIMARY KEY:确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录

FOREIGN KEY:保证一个表中的数据匹配另一个表中的值的参照完整性

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

1.2 NULL约束

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

sql 复制代码
-- 设置学生表结构
CREATE TABLE student_5 (
	id INT NOT NULL,
	sn INT,
	name VARCHAR(20), 
	qq_mail VARCHAR(20)
);

1.3 NUIQUE:唯一约束

指定sn列中的值唯一且不重复的:

sql 复制代码
-- 重新设置学生表结构
DROP TABLE IF EXISTS student_5;
CREATE TABLE student (
	id INT NOT NULL,
	sn INT UNIQUE,
	name VARCHAR(20),
	qq_mail VARCHAR(20)
);

1.4 DEFAULT:默认值约束

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

sql 复制代码
-- 重新设置学生表结构
DROP TABLE IF EXISTS student_5;
CREATE TABLE student (
	id INT NOT NULL,
	sn INT UNIQUE,
	name VARCHAR(20) DEFAULT '无名氏',
	qq_mail VARCHAR(20)
);

1.5 PRIMARY KEY:主键约束

指定id列为主键:

sql 复制代码
-- 重新设置学生表结构
DROP TABLE IF EXISTS student_5;
CREATE TABLE student (
	id INT NOT NULL PRIMARY KEY,
	sn INT UNIQUE,
	name VARCHAR(20) DEFAULT '无名氏',
	qq_mail VARCHAR(20) 
);

primary key 一般用于主要的字段,如id序号

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

sql 复制代码
-- 主键是 NOT NULL 和 UNIQUE 的结合,可以不用 NOT NULL
id INT PRIMARY KEY auto_increment

1.6 FOREIGN KEY:外键约束

外键用于关联其他表主键唯一值

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

案例:

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

    sql 复制代码
    -- 创建班级表,有使用MySQL关键字作为字段时,需要使用``来标识
    CREATE TABLE classes_5 (
    	id INT PRIMARY KEY auto_increment,
    	name VARCHAR(20),
    	`desc` VARCHAR(100)
    );
  • 创建学生表student,一个学生对于一个班级,一个班级对应多个学生。使用id为主键,class_id为外键,关联班级表id

    sql 复制代码
    DROP TABLE IF EXISTS student_5;
    CREATE TABLE student (
    	id INT NOT NULL PRIMARY KEY auto_increment,
    	sn INT UNIQUE,
    	name VARCHAR(20) DEFAULT '无名氏',
    	qq_mail VARCHAR(20),
        classes_id int,
       	FOREIGN KEY (classes_id) REFERENCES classes_5(id)
    );

1.7 CHECK约束

MySQL使用时不报错,但忽略该约束(这个约束的使用率不高)

sql 复制代码
create table test_user (
	id int,
	name varchar(20),
	sex varchar(1),
	check (sex = '男' or sex = '女')
);

2. 表的关系

2.1 一对一

sql 复制代码
-- 一个人只能对应一张身份证,即两个表的id要相同
create table person (
    person_id int primary key, name varchar(20)
);
create table id_card (
    person_id int primary key, 
    name varchar(20),
    birthday datetime,
    address varchar(30),
    foreign key (person_id) references person(person_id)
);

2.2 一对多

sql 复制代码
-- 一个班级可以有多个学生(即能有不同的学生id),所以要为学生设置一个class_id来和class中的id匹配
 create table classes (id int primary key, class_name varchar(20));
 create table student (
     student_id int primary key, 
     name varchar(20), 
     class_id int, 
     foreign key (class_id) references classes(id)
);

2.3 多对多

sql 复制代码
-- 一个课程中间表(考试成绩表)既要和学生对应,也要和课程对应
create table course (course_id int primary key, course_name varchar(20));
create table score (
    id int primary key,
    score int, 
    student_id int,
    course_id int,
    foreign key (student_id) references student(student_id),
    foreign key (course_id) references course(course_id)
);

3. 特殊新增

我们可以将查询到的结果插入到新的表中

语法:

sql 复制代码
INSERT INTO table_name [(column [, column ...])] SELECT ...

案例:创建一张学生用户表,设计有id学号 name姓名, 年龄age的字段,需要把已有的学生数据复制进来,刚创建且没有被复制赋值的字段为NULL

sql 复制代码
-- 给学生表插入数据
-- 因为学生表的id已经链接了班级表的id,所以需要先给班级表赋值才能给学生表插入数据
-- (且插入学生表的班级id必须是班级表里能够对应上的)
insert into classes values (707, '计科七班'), (808, '软工八班');
insert into student values (101, '张三', 707), (201, '里斯', 808);

-- 将学生表中能够赋值的数据复制到学生用户表中
insert into test_user (id, name) select student_id, name from student;

4. 查询

4.1 聚合查询

4.1.1 聚合函数

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

函数 说明
COUNT([DISTINCT] expr) 返回查询到的数据的 数量
SUM([DISTINCT] expr) 返回查询到的数据的 总和,不是数字没有意义
AVG([DISTINCT] expr) 返回查询到的数据的 平均值,不是数字没有意义
MAX([DISTINCT] expr) 返回查询到的数据的 最大值,不是数字没有意义
MIN([DISTINCT] expr) 返回查询到的数据的 最小值,不是数字没有意义
  • COUNT

    sql 复制代码
    -- 统计班级共有多少同学
    SELECT COUNT(*) FROM student;
    
    -- 统计班级存在的学号一共有几个
    SELECT COUNT(class_id) FROM student;

    注:当查询结果带有null值时,非count(*)的其它count()查询不会将null值的记录计入数据

    sql 复制代码
    insert into student(student_id, name) values (125, '小力');
    select count(class_id) 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 复制代码
    -- 返回英语最低分
    select min(english) from exam_result;
    
    -- 返回 > 60分 的英语最低分
    select min(english) from exam_result where english > 60;
4.1.2 GROUP BY 子句

SELECT 中使用GROUP BY 子句可以对指定列进行分组查询

条件:使用GROUP BY 进行分组查询时,SELECT指定的字段必须是"分组依据字段",其它字段若想出现在SELECT中则必须包含在聚合函数中。

案例:

  • 准备测试表及数据:职员表,有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)
    );
  • 查询每个角色的最高工资、最低工资和平均工资

    sql 复制代码
    select role, max(salary), min(salary), avg(salary) from emp group by role;
4.1.3 HAVING

GROUP BY 子句进行分组以后,需要对分组结果再进行条件过滤时 。不能使用WHERE语句,而需要用HAVING

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

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

4.2 联合查询

4.2.1 初始化

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

在这里我们先初始化测试数据:

sql 复制代码
drop table if exists classes;
drop table if exists student;
drop table if exists course;
drop table if exists score;

create table classes (id int primary key auto_increment, name varchar(20), `desc` varchar(100));

create table student (id int primary key auto_increment, sn varchar(20),  name varchar(20), qq_mail varchar(20) , classes_id int);

create table course(id int primary key auto_increment, name varchar(20));

create table score(score decimal(3, 1), student_id int, course_id int);

insert into classes(name, `desc`) valu
	('22级计科7班', '学习了计算机原理、Python、C、Java、数据结构和算法'),
	('19级汉语言3班', '学习了中国传统文学'),
	('23级自动化2班', '学习了机械自动化、单片机');

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 操作步骤

在进行多表查询时,一般可分为以下四个步骤:

  1. 先进行笛卡尔积
  2. 再指定连接条件
  3. 其次可指定其它条件
  4. 最后针对列进行精简

案例:查询"许仙"同学的成绩

  • 笛卡尔积

    sql 复制代码
    -- 指定两个有关联的表进行笛卡尔积
    select * from student, score;
  • 指定连接条件

    sql 复制代码
    -- 指定连接条件精简结果(可以通过点【表名.】调用字段)
    select * from student, score where student.id = score.student_id; 
  • 再根据需求补充其它条件

    sql 复制代码
    -- 找许仙的成绩
    select * from student, score where student.id = score.student_id and student.name = '许仙';
  • 针对上面的最后再进行精简

    sql 复制代码
    select student.name, score.score from student, score where student.id = score.student_id and student.name = '许仙';

注:整个过程也可以总结为一句sql语句来调用

sql 复制代码
select student.name, score.score from student, score where student.id = score.student_id and student.name = '许仙';
4.2.3 内连接

其操作步骤与上述步骤相同,只是语法不同而已

语法:

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

--也可以这样做
select 字段 from 表1 别名1, 表2 别名2 where 连接条件 and 其它条件;

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

案例:

  • 查询"许仙"同学的成绩

    sql 复制代码
    select stu.name, sco.score from student as stu join score as sco on stu.id = sco.student_id and stu.name = '许仙';
    
    select stu.name, sco.score from student as stu, score as sco where stu.id = sco.student_id and stu.name = '许仙';
  • 查询所有同学的总成绩,及同学的个人信息

    sql 复制代码
    -- 成绩表对学生表是多对一关系,查询总成绩是根据成绩表的同学id来进行分组的
    select stu.sn, stu.name, stu.qq_mail, sum(sco.score) from student as stu join score as sco on stu.id = sco.student_id group by sco.student_id;
  • 查询所有同学的成绩,及同学的个人信息

    这里需要将三张表进行笛卡尔积,先找到表之间的关联关系,将有关联的两张表进行笛卡尔积,再将得到的结果和另一张表计算笛卡尔积

    sql 复制代码
    -- student 和score 计算笛卡尔积
    select stu.id, stu.sn, stu.name, stu.qq_mail, sco.score, sco.course_id, cou.name from student as stu join score as sco on stu.id = sco.student_id join course as cou on sco.course_id = cou.id order by stu.id;
4.2.4 外连接

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

语法:

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

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

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

sql 复制代码
-- "老外学中文"同学 没有考试成绩,也显示出来了
select * from student as stu left join score as sco on stu.id = sco.student_id;
-- 对应的右外连接
select * from student as stu right join score as sco on stu.id = sco.student_id;
4.2.5 自连接

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

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

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

-- 再查询成绩表中,"计算机原理"成绩比"Java"成绩好的信息
select s1.* from score as s1, score as s2 where s1.student_id = s2.student_id and s1.score < s2.score and s1.course_id = 1 and s2.course_id = 3;
4.2.6 合并查询

在实际应用中,为了合并多个select的执行结果,可以使用集合操作符unionunion all。使用unionunion all 时,前后查询的结果集中,字段需要一致(union左右两侧sql可以是查询两个不同的表,而or不行)

  • union

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

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

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

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

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

    sql 复制代码
    -- union all的结果集中出现重复的数据Java
    select * from course where id < 3 union all select * from course where name = 'Java';
相关推荐
m0_7482448316 分钟前
StarRocks 排查单副本表
大数据·数据库·python
C++忠实粉丝26 分钟前
Redis 介绍和安装
数据库·redis·缓存
wmd1316430671241 分钟前
将微信配置信息存到数据库并进行调用
数据库·微信
是阿建吖!1 小时前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
凡人的AI工具箱1 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
ClouGence1 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存
m0_748236581 小时前
《Web 应用项目开发:从构思到上线的全过程》
服务器·前端·数据库
苏三说技术1 小时前
Redis 性能优化的18招
数据库·redis·性能优化
Tttian6222 小时前
基于Pycharm与数据库的新闻管理系统(2)Redis
数据库·redis·pycharm
做梦敲代码2 小时前
达梦数据库-读写分离集群部署
数据库·达梦数据库