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';
相关推荐
Karoku06633 分钟前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch
小技与小术2 小时前
数据库表设计范式
数据库·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
运维·服务器·数据库·sql·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器
数据库·sql·mysql·oracle·实验报告
Loganer2 小时前
MongoDB分片集群搭建
数据库·mongodb
LKID体2 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
刘大浪2 小时前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
一只爱撸猫的程序猿2 小时前
简单实现一个系统升级过程中的数据平滑迁移的场景实例
数据库·spring boot·程序员
无敌岩雀2 小时前
MySQL中的索引
数据库·mysql
a_安徒生3 小时前
linux安装TDengine
linux·数据库·tdengine