一、数据库的约束
1.1约束类型
NOT NULL-指示某列不可以存储NULL值
UNIQUE- 保证某列的每行必须有唯一的值
DEFAULT-规定没有给列赋值时的默认值
PRIMARY KEY- NOT NULL和UNIQUE的结合,确保某列有唯一标识,有助于更快找到某表记录
FOREIGN KEY-保证一个表的数据匹配另一个表的值的参照完整性
CHECK-保证列中的值符合指定要求
1.2NULL约束
创建表时,可以指定某列不为空:
DROP TABLE IF EXISTS student;
CREATE TABLE student(
id INT NOT NULL,
sn INT ,
name VARCHAR(20),
qq_email 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 默认值约束
--重新设置学生表结构
DROP TABLE IF EXISTS student;
CREATE TALBE student(
id INT NOT NULL,
sn INT UNIQUE,
name VARCHAR(20) DEFAULT 'unkown',
qq_mail VARCHAR(20)
);
1.5 PRIMARY KEY 主键约束
指定id列为主键
重新设置学生表结构
DROP TABLE IF EXISTS student;
CREATE TALBE student(
id INT PRIMARY KEY AUTO_INCREMENT,
sn INT UNIQUE,
name VARCHAR(20) DEFAULT 'unkown',
qq_mail VARCHAR(20)
);
AUTO_INCREMENT 自增,当插入数据对应字段不给值时,使用最大值+1
主键PRIMARY KEY是NOT NULL和UNIQUE 的结合,可以不同NOT NULL
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为外键
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.7 CHECK 约束
DROP table if exists test_user;
create table test_user (
id int,
name varchar(20),
sex varchar(1),
check (sex ='男' or sex='女')
);
二、表的设计
三大范式: 一对一,一对多,多对多
一对一
一对多
多对多
他们之间的联系是通过外键进行连接
三、新增
插入查询结构
语法:INSERT INTO table_name [(column [, column ...])] SELECT ...
案例:创建一张用户表,设计有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;
四、查询
4.1聚合查询
常见的统计总数,计算平局值等操作,可以使用聚合函数来实现,常见的聚合函数有:
函数 | 说明 |
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;
*SUM
-- 统计数学成绩总分
SELECT SUM(math) FROM exam_result;
-- 不及格 < 60 的总分,没有结果,返回 NULL
SELECT SUM(math) FROM 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.2 GROUP BY子句
SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。需要满足:使用 GROUP BY 进行分组查询时,SELECT 指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT 中则必须包含在聚合函数中。
SELECT column1,sum(column2),.. from table group by column1,column3;
案例:准备测试表及数据:职员表,有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;
4.3 HAVING语句
GROUP BY子句分组以后,需要对分组结果进行条件过滤时,不能使用WHERE 语句,需要使用HAVING
*显示平均工资低于1500的角色和它的平均工资
SELECT role,avg(salary) from emp group by role
having avg(salary)<1500;
4.4联合查询
实际开发中,数据来自不同的表,所以需要多边联合查询,多表查询是对多张表的数据取笛卡尔积
例如 a表 b表 笛卡尔积
注意:关联查询可以对关联表使用别名
下面的操作同时借用了不同表的数据,来进行总体操作
--添加新课程
INSERT INTO classes (name,'desc') values
("计算机科学与技术",'学习软硬件的原理');
--添加新学生
INSERT INTO student(sn,name,email,classes_id) values
('001','贝吉塔','xx@outlook.com',1);
--向课程里添加新课程名字
INSERT INTO course (name) values
('java'),('c++'),('计算机组成原理');
--插入贝吉塔同学的成绩
INSERT INTO score(score,student_id,course_id) values
(70.5,1,1);
4.5 内连接
语法:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2,别名2 where 连接条件 and 其他条件 ;
案例:
.查询 贝吉塔同学的成绩
--将 student表和score表连接,并且两个都起了别名,方便输入
select sco.score from student stu innner 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.email,
sum(sco.score)
FROM
student stu
JOIN score sco ON stu.id=sco.student_id
GROUP BY
sco.student_id;
4.6外连接
外连接分为左外连接和右外连接,如果联合查询,
左侧的表完全显示就是左外连接
右侧的表完全显示就是右外连接
语法:
--左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
--右外连接,表2完全显示
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;
4.7自连接
自连接是同一张表连接自身去查询
案例:
显示所有“计算机原理”成绩比“Java”成绩高的成绩信息
--先查询'计算机组成原理’和‘java’课程的id
select id,name from course where name='java' or name='计算机原理';
--再查询成绩表中,‘计算机组成原理’成绩比‘java’成绩好的信息
-- 使用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;
4.8子查询
子查询就是嵌入在其他sql语句中的select语句,也叫嵌套查询
单行子查询:返回一行记录的子查询
查询与“不想毕业” 同学的同班同学
select * from student where classes_id=(select classes_id from student where
name='不想毕业');
多行子查询:返回多行记录的子查询
案例:
1.[NOT] IN 关键字
查询‘语文’或‘英文’课程的成绩信息
-- 使用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!='英文');
2.[NOT] EXISTS关键字
-- 使用 EXISTS
select * from score sco where exists (select sco.id from course cou
where (name='语文' or name='英文') and cou.id = sco.course_id);
-- 使用 NOT EXISTS
select * from score sco where not exists (select sco.id from course cou
where (name!='语文' and name!='英文') and cou.id = sco.course_id);
from语句中使用子查询,子查询语句出现在from子句中,这里是把一个子查询当做一个临时表来使用
4.9合并查询
在实际应用中,为了合并多个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='英文';
五、内容重点总结
约束类型 | 说明 | 示例 |
NULL 约束 | 使用 NOT NULL 指定列不为空 | name varchar(20) not null, |
UNIQUE 唯一约束 | 指定列为唯一的、不重复的 | name varchar(20) unique, |
DEFAULT 默认值约束 | 指定列为空时的默认值 | age int default 20, |
主键约束 | NOT NULL 和 UNIQUE 的结合 | id int primary key, |
外键约束 | 关联其他表的 主键 或 唯一键 | foreign key (字段名) references 主表 (列) |
CHECK 约束(了解) | 保证列中的值符合指定的条件 | check (sex ='男' or sex='女') |
表的关系
1. 一对一:
2. 一对多
3. 多对多:需要创建中间表来映射两张表的关系
新增:
INSERT INTO table_name [(column [, column ...])] SELECT...
查询:
1. 聚合函数:
MAX、MIN、AVG、COUNT、SUM
2. 分组查询:
GROUP BY... HAVING ...
3. 内连接
select ... from 表1,表2 where 条件
-- inner可以缺省
select ... from 表1 join 表2 on 条件 where 其他条件
4.外连接:
select ... from 表1 left/right join 表2 on 条件 where 其他条件
5.自连接:
select ... from 表1,表1 where 条件
select ... from 表1 join 表1 on 条件
6.子查询:
-- 单行子查询
select ... from 表1 where 字段1 = (select ... from ...);
-- [NOT] IN
select ... from 表1 where 字段1 in (select ... from ...);
-- [NOT] EXISTS
select ... from 表1 where exists (select ... from ... where 条件);
-- 临时表:form子句中的子查询
select ... from 表1, (select ... from ...) as tmp where 条件
7.合并查询:
-- UNION:去除重复数据
select ... from ... where 条件
union
select ... from ... where 条件
-- UNION ALL:不去重
select ... from ... where 条件
union all
select ... from ... where 条件
-- 使用UNION和UNION ALL时,前后查询的结果集中,字段需要一致
SQL查询中各个关键字的执行先后顺序:
from > on> join > where > group by > with > having >select > distinct > order by > limit