目录
一.数据库中创建表时的约束
1.约束类型
类型 | 含义 |
NOT NULL | 指示某列不能存储 NULL 值 |
UNIQUE | 保证某列的每行必须有唯一的值 |
DEFAULT | 规定没有给列赋值时的默认值 |
PRIMARY KEY | 主键约束,NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录 |
FOREIGEN KEY | 外键约束,保证一个表中的数据匹配另一个表中的值的参照完整性 |
2.约束类型的详细说明和例子
前提:需要在自己指定的库里面创建表(如果不太懂,可以看前面的博客)
例子:在创建学生对象的时候使用约束类型
(1)为创建的每个数据设置约束类型
drop table if exists classes;
create table classes(
id int primary key auto_increment,
class int
);
drop table if exists student;
create table student(
id int primary key auto_increment,
-- 主键约束(整型长搭配自增,每次插入省略给id,因为自动就会给值)
stu_name varchar(20) default 'unknown',
-- 默认值约束(这里默认约束为unknown)
qq_mail varchar(20) unique,
-- 唯一约束,不重复
class_id int not null,
-- 非空约束
foreign key (class_id) references classes(id)
);
创建成功显示:
(2)插入时注意自己设置的类型
因为在插入数据的时候就会用到这些类型约束。
正确插入代码:
insert into
classes (class)
values
(1),
(2),
(3);
insert into
student (stu_name, qq_mail, class_id)
values
('张三', '157@qq.com', 1),
('李四', '163@qq.com', 2),
('王五', '186@qq.com', 3);
成功演示:
对于超过约束条件的就会插入失败,如下所示:
代码:
-- 插入成功,名字默认unknow
insert into
student (qq_mail, class_id)
values
('123@qq.com', 1);
-- 外键约束,插入失败
insert into
student (qq_mail, class_id)
values
('123@qq.com', 4);
-- 查询插入后的表,这里的id是自增且唯一
select
*
from
student;
二.表的结构
通过外键来对表进行连接
1.一对一
2.一对多
3.多对多
三.查询进阶
1.聚合查询常用函数
函数 | 说明(不是数字没有意义) |
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的 总和 |
AVG([DISTINCT] expr) | 返回查询到的数据的 平均值 |
MAX([DISTINCT] expr) | 返回查询到的数据的 最大值 |
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值 |
-- 聚合查询的练习
-- 查询学生总数
select
COUNT(0) stu_count
from
student;
-- 查询id的总和
select
SUM(id) id_sum
from
student;
-- 查询id中的最大值
select
MAX(id) id_max
from
student;
-- 查询id中的最小值
select
MIN(id) id_min
from
student;
-- 查询id的平均值
select
AVG(id) id_avg
from
student;
查询结果:
2.GROUP BY(分组查询)语句的使用
(1)说明
SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。需要满足:使用 GROUP BY 进行分组查询时,SELECT 指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT 中则必须包含在聚合函数中。
(2)语法
select 列名或聚合函数,... from 表名 group by 依据的列名或聚合函数;
(3)例子
1.创建表
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.27),
('李四', '游戏陪玩', 2000.98),
('王五', '游戏角色', 999.18),
('赵六', '游戏角色', 333.5),
('田七', '游戏角色', 700.45),
('刘备', '董事长', 12000.34);
2.查询要求
查询每个角色的最高工资和最低工资
SELECT
role,
MIN(salary) min_salary,
MAX(salary) max_salary
FROM
emp
GROUP BY
role;
注意:因为select后是显示的结果集,如果上面还需要显示名字,不会报错,但是会出现与所要结果有很大的差异。
3.HAVING的使用
(1)使用说明
如果分组以后还需要对结果进行过滤,不能使用where,只能使用having来进行过滤。
(2)语法
group by 分组后跟having。
(3)例子
显示平均工资低于1500的角色和他的平均工资
select
role,
avg(salary)
from
emp
group by
role
having
avg(salary) < 1500;
注意:having中的内容必须在select查询的结果集中,否则会出现错误。
四.联合查询
联合查询是根据多表进行查询,而多表查询是对数据取笛卡尔积。
笛卡尔积:如果有两个表,第一个表(M)的每一行与另一张表(N)的每一行都进行匹配,最终的结果集中有M*N行。但是有些数据是无效的,所以需要一些条件来过滤这些无效信息。
1.内连接
(1)语法
1.select 字段 from 表1 别名 ,[inner] join 表2 别名 on连接条件 and 其他 条件;
2.select 字段 from 表1 别名,表2 别名 where 连接条件 and 其他条件;
(2)例子
准备查询的数据
DROP TABLE IF EXISTS classes;
-- 创建班级表
CREATE TABLE classes (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20),
`desc` VARCHAR(100)
);
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)
);
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
classes(name, `desc`)
values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班', '学习了中国传统文学'),
('自动化2019级5班', '学习了机械自动化');
insert into
student(sn, name, qq_mail, classes_id)
values
('09982', '张三', 'zhangsan@qq.com', 1),
('00835', '李四', null, 1),
('00391', '王五', null, 1),
('00031', '赵六', 'xuxian@qq.com', 1),
('00054', '田七', null, 1),
('51234', '小明', 'say@qq.com', 2),
('83223', '小李', 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),
-- 小李
(80, 7, 2),
(92, 7, 6);
要求:查询赵六同学的成绩
这里通过内连接将表关联后再通过id进行过滤
-- 查询赵六的所有成绩,结果集中显示每个课程名和对应的成绩
select
cou.name,
sco.score
from
student stu
join score sco on stu.id = sco.student_id
join course cou on cou.id = sco.course_id
where
stu.name = '赵六';
结果显示:
2.外连接
外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接。
(1)引入
查询要求:查询所有同学的成绩及个人信息
-- 查询所有同学的成绩及个人信息
select
stu.id,
stu.sn,
stu.name,
stu.qq_mail,
sco.score,
cou.id,
cou.name
from
student stu
join score sco on stu.id = sco.student_id
join course cou on cou.id = sco.course_id
order by
stu.id;
如果内连接中某个表中的数据中存在null则在最终查询后则不会显示,如上面查询所有同学成绩和个人信息,因为老外没有成绩,所以最后查询的结果,没有显示老外,如果我们还要该同学,那么就需要外连接来进行实现。
(2)语法
1.左外连接
select 字段名 from 表名 left join 表名 on 连接条件;
2.右外连接
select 字段名 from 表名 right join 表名 on 连接条件;
(3)例子
实现所有学生成绩及个人信息查询
-- 查询所有同学的成绩及个人信息
select
stu.id,
stu.sn,
stu.name,
stu.qq_mail,
sco.score,
cou.id,
cou.name
from
student stu
left join score sco on stu.id = sco.student_id
left join course cou on cou.id = sco.course_id
order by
stu.id;
注意:这里的两张表都需要左外连接,否则还是不会显示老外同学的成绩。
3.自连接
(1)说明
在同一张表连接自身进行查询,这里是对于同一张表的不同行进行比较,通过与自身连接从而简单了查询过程。
(2)语法
select 字段 from 表名1 别名1 join on 表名1 别名2 on 连接条件 and其他条件;
(3)例子
查询java成绩比计算机原理成绩高的学生
-- 查询java成绩比计算机原理成绩高的成绩信息(查询的前提是已知java和计算机原理的课id)
select
stu.name,
sc1.student_id,
sc1.score 'java成绩',
sc2.score '计算机原理成绩'
from
score sc1
join score sc2 on sc1.student_id = sc2.student_id
join student stu on sc1.student_id = stu.id
and sc1.course_id = 1
and sc2.course_id = 3
and sc1.score > sc2.score;
4.子查询
(1)说明
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询。相当于select中嵌套了select。
(2)语法
select 字段名 from 表1 where 条件=(select 字段名 from 表2);
注意:里面的select 查询相当于一个临时表,如果需要表1的字段需要与临时表返回的结果集进行比较,则临时表需要有别名。下面通过例子来进行理解子查询。
(3)例子
1.查询class_id为1的所有学生的信息
-- 查询和张三同学是同班同学的所有信息
select
stu.*
from
student stu
where
stu.classes_id = (
select
classes_id
from
student
where
name = '张三'
);
2.查询所有比中文系2019级3班平均分高的所有班级
-- 查询所有比中文系2019级3班平均分高的所有班级
select
score.*
from
score,
(
select
avg(sco.score) avg_score
from
student stu
join classes cla on stu.classes_id = cla.id
join score sco on sco.student_id = stu.id
where
cla.name = '中文系2019级3班'
) tmp
where
score.score > tmp.avg_score;
注意:子查询中还使用了内连接,因为这里设计到了3张表,其中学生表和另外两张表进行关联。
5.合并查询
(1)概念
通过union 和union all 合并多个select查询结果,条件是前后查询的结果集字段需要一致。
union合并查询会自动去重;union all合并查询并不会去重。
(2)语法
select 字段名 from 表名... and 其他条件 union select 字段名 from 表名... and 其他条件;
select 字段名 from 表名... and 其他条件 union all select 字段名 from 表名... and 其他条件;
(3)例子
使用合并查询课程id<3或者是英文的课程信息
1.union使用
-- 查询课程id小于3或者课程为英文的所有课程
select
*
from
course
where
id < 3
union
select
*
from
course
where
name = '英文';
注意:这里也可以or也可以进行实现,在实际中使用哪种方法来进行查询,只要能将指定结果集查询出来都可以。
2.union all 使用
查询课程id小于3或者课程为java的课程信息
-- 查询课程id<3 或者课程为java的课程信息(结果集不去重,使用union all)
select
*
from
course
where
id < 3
union
all
select
*
from
course
where
name = 'Java';