数据库设计只需要满足第三范式:
第一范式
表中每一列都具有原子性,不可分割;eg:不能在联系方式列中同时存邮箱和电话。
第二范式
在第一范式的基础上,需要满足:(1)如果表是单主键,那么主键以外的列必须完全依赖于主键;(2)如果表是联合主键,那么主键以外的列必须完全依赖于联合主键。
eg:订单ID和商品ID作为联合主键。
第三范式
在第二范式的基础上,表中的非主键列必须和主键列直接相关,即非主键列之间不能相关依赖。
整数类型
TINYINT、SMALLINT、MEDIUMINT、INT和BIGINT
浮点数类型和定点数类型
FLOAT 和 DOUBLE;DECIMAL
字符串类型
CHAR(m):m是字符串最大长度,不管插入实际值是多少,所占存储空间都是m个字节。
VARCHAR(m):数据所占用的字节数为实际长度加1。
文本类型
TINYTEXT,MEDIUMTEXT,TEXT,LONGTEXT表示大文本数据
日期和时间类型
YEAR、DATE、TIME、DATETIME和TIMESTAMP
二进制类型
常用BLOB存储二进制类型的数据,图片,pdf文档等。
# 删除数据库
drop database db1;
# 创建数据库
create database db1;
# 显示数据库
show create database db1 ;
# 修改数据库字符集
alter database db1 character set gbk;
# 切换数据库
use db1;
# 设置主键
学号 VARCHAR(100) primary key auto_increment,
# 设置联合主键
primary key(学号,姓名),
# alter设置主键约束
alter table student add primary key(学号);
# 设置非空约束
alter table 从表名 add constraint 外键名(从表外键字段) references 主表(主键字段);
alter table 从表名 add constraint 外键名 foreign key(从表外键字段) references 主表(主键字段);
# 设置非空约束
姓名 VARCHAR(100) not null,
# 设置唯一性约束
学号 VARCHAR(100) unique,
# 设置默认值约束
性别 VARCHAR(100) default '女',
# 切换数据库
use mybatisdatabase;
# 创建表
drop table if exists student;
create table student(
学号 VARCHAR(100),
姓名 VARCHAR(100),
出生日期 VARCHAR(100),
性别 VARCHAR(100)
);
# 更新数据
update student(学号,姓名,出生日期,性别) values ('0001' , '一一' , '1989-01-01' , '男');
insert into student(学号,姓名,出生日期,性别) values ('0002' , '二二' , '1990-12-21' , '女');
# 查看表
show create table student;
# 查看表的字段
describe student;
# 修改表的字符集
alter table student character set utf8;
# 修改表名
alter table student rename to 学生表;
alter table 学生表 rename to student;
# 修改字段名
alter table student change 学号 id varchar(100);
alter table student change id 学号 varchar(100);
# 修改字段数据类型
alter table student modify 学号 int;
alter table student modify 学号 varchar(100);
# 新增字段
alter table student add 新字段 int after 姓名;
# 删除字段
alter table student drop 新字段;
# 插入数据
insert into student(学号,姓名,出生日期,性别) values ('0001' , '一一' , '1989-01-01' , '男');
insert into student(学号,姓名,出生日期,性别) values ('0002' , '二二' , '1990-12-21' , '女');
insert into student(学号,姓名,出生日期,性别) values ('0003' , '三三' , '1995-01-01' , '男');
insert into student(学号,姓名,出生日期,性别) values ('0004' , '四四' , '1996-01-01' , '女');
# 更新一条记录
update student set 姓名='aa',性别='女' where 学号='0001';
# 更新所有记录
update student set 性别 = '男';
# 删除数据,delete和truncate的区别在于,delete可以使用where子句删除部分记录
# truncate语句只能用于删除表中所有记录;delete是DML语句,truncate属于DDL语言
# 删除记录
delete from student where 学号='0001';
# 删除表中所有记录
delete from student;
# 删除表所有记录
truncate table student;
所谓聚合,就是将多行汇总成一行;其实,所有聚合函数均如此——输入多行,输出一行。
例如,统计某个字段的最大值、最小值、平均值等。为此,MySQL中提供了聚合函数来实现这些功能。
# 统计表中值不为null的数据个数
select count(*) from student;
# 统计表中age字段的最大值
select max(age) from student;
# 统计表中age字段的最小值
select min(age) from student;
# 统计表中age字段的最小值
select sum(age) from student;
# 统计表中age字段的最小值
select avg(age) from student;
# 简单查询
select 学号,性别 from student where 姓名='一一';
select * from student;
# 从查询结果中删除重复数据,只作用于一个列名
select distinct 性别 from student;
# 条件
select 学号,性别 from student where 姓名='一一';
select 学号,性别 from student where 学号 in ('0001','0002','0003');
# 判断字段是否不在指定集合中
select 学号,性别 from student where 学号 not in ('0001','0002','0003');
select 学号,性别,姓名 from student where 学号 between '0001' and '0003';
# 条件与
select 学号,性别,姓名 from student where 学号>'0002' and 性别='女';
# 条件或
select 学号,性别,姓名 from student where 学号>'0002' or 性别='女';
# 匹配整个字符串
select 学号,性别,姓名,出生日期 from student where 姓名 like '一一';
# %用于匹配任意长度的字符串,匹配以'一'结尾的姓名
select 学号,性别,姓名,出生日期 from student where 姓名 like '%一';
# _用于匹配单个字符
select 学号,性别,姓名,出生日期
# 查询学生表中前5位学生
select * from student limit 5;
# 查询学生表中年纪最小的3位学生
select * from student order by age asc limit 3;
# 统计男女的数量
select count(*) 性别 from student group by 性别;
# 查询学号大于'0002'的学生并将结果升序排列
select * from student where 学号>'0002' oder by 学号 asc;
# 查询学号大于'0002'的学生并将结果降序排列
select * from student where 学号>'0002' oder by 学号 desc;
内连接使用比较运算符对两个表中的数据进行比较并列出与连接条件匹配的数据,组合成新的记录。内连接查询中只有满足条件的记录才能出现在查询结果中。
select 字段 from 主表 inner join 从表 on 主表和从表的查询条件 ;
# 带限制条件的内连接
select employee.name,employee.eage,department.dname from department inner join employee on department.did = employee.departmentid where employee.eage>20 order by employee.eage desc;
返回包括左表中的所有记录和右表中符合连接条件的记录。如果左表的某条记录在右表中不存在则在右表中显示为空。
eg:查询每个部门的部门id,部门名称以及该部门的所有员工姓名:
select department.did, department.dname, employee.ename from department left join employee on department.did = employee.departmentid;
返回包括右表中的所有记录和左表中符合连接条件的记录。如果右表中的某条记录在坐标中不存在则在右表中显示为空。
eg:查询每个部门的id,部门名称以及该部门所有员工的名字:
select department.did,department.name,employee.ename from department right join employee on department.did = employee.departmentid;
例如,老师表teacher和学生表student之间可以建立一个老师学生关系表,通过这个中间表,进行多对多查询。
eg:查询名叫luck的学生有几位老师:
select * from teacher where teacherid in (select from teacher_student_relation where sid = (select studentid from student where studentname='lucy'));
子查询是指一个查询语句嵌套在另一个查询语句内部的查询;
# 查询yiyi同学所在班级的信息
select * from class where cid = (select classid from student where sname='yiyi');
# 查询年纪大小为21的学生所在班级信息
select * from class where cid in(select classid from student where sage=21)
# 假若yiyi同学在student表中,则从班级表中查询所有信息
select * from class where exists (select classid from student where sname='yiyi')
# 查询比任一学生所属班级号还大的班级编号
select * from class where cid > any (select classid from student)
# 查询比任一学生所属班级号还大的班级编号
select * from class where cid > all (select classid from student)
事务是针对数据库的一组操作(由一条或多条SQL语句组成)进行管控。事务中的语句要么都执行,要么都不执行。
原子性
事务具有原子性,事务中的语句要么都执行,要么都不执行。
一致性
事务执行前后,数据库的一致性状态保持不变,比如,用户A和用户B账户的钱一共1000,经过多次转账,事务结束后,用户A和用户B账户的钱总和仍是1000。
隔离性
多个并发事务之间要隔离,即多个并发事务之间必须同步执行。不能同时操作同一个表。
持久性
事务一旦提交,其所作的修改就会被持久到数据库中。
通常情况下数据库是被多线程并发访问的,所以很容易出现多个线程同时开启事务的情况。在这种情况下,可能出现脏读,重复读,幻读。
为了避免这些情况,需要为事务设置隔离级别。MySQL有4种隔离级别。
实际开发中,会遇到经常需要重复使用某一功能的情况,MySQL中引入存储过程,存储过程是指一条或多条SQL语句的集合,存储过程将多条SQL语句封装为一个代码块,便于重复使用,提高开发效率。
SQL语句需要先编译然后执行,存储过程时将完成特定功能的SQL语句集编译后存储在数据库中,用户可以通过传参的方式对存储过程进行调用,存储过程看起来像是函数。
编写存储过程:
delimiter //
# 创建存储过程
create procedure procedureHelloWorld(in sage int)
# begin和end之间是存储过程体
begin
select * from student where age>sage;
end
delimiter ;
# 调用存储过程
call procedureHelloWorld(15);
利用**DELIMITER //**把分隔符还原为默认分隔符; 。使得编译器不把存储过程识别为普通SQL语句进行编译。
游标提供了一种对从表中检索出的数据进行操作的灵活手段。就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。
# 定义游标
declare studentCursor cursor for select * from student;
# 打开游标
open studentCursor;
# 使用游标获取列的值
Fetch next from studentCursor into studentID,studentName,studentAge;
# 显示结果
select studentID,studentName,studentAge,studentGender;
# 关闭游标
close studentCursor;
end
视图是从一个或多个表中导出的表,是一种虚拟存在的表,可对视图进行表操作,通过视图更新数据时其实是在更新基本表中的数据。相对于直接操作基本表,视图具有以下优点:
AS:表示指定视图要执行的操作。
# 创建视图
create view if exists view_student;
create view view_student as select math,chinese from student;
# 查看视图
select * from view_student;
AS:表示指定视图要执行的操作。
# 创建视图
drop view if exists view_student_studentInfo;
create view view_student_studentInfo(id,name,province,fname.mname) as select student.sid,student.sname,studentInfo.province,studentInfo.fatherName,studentInfo.motherName from student inner join studentInfo on student.sid=studentInfo.sid;
# 查看视图
select * from view_student_studentInfo;
数据库查询分为顺序查询和索引查询,索引查询需要建立索引,加快数据表的查询和排序,但存储索引需要占据一定磁盘空间,创建和维护索引消耗的时间随着数据量的增加而增加。
drop table if exists student;
create table student(
学号 VARCHAR(100),
姓名 VARCHAR(100),
出生日期 VARCHAR(100),
性别 VARCHAR(100),
# 建立普通索引
index(学号)
# 创建唯一性索引
unique index uniqueindex(学号),
# 单列索引
unique singleIndex(学号(20)),
# 多列索引
index mulIndex(学号,姓名(20))
);
给已有表创建索引:
create index bookindex on book(bookid);
alter table book add index bookIndex(bookid);
删除索引:为了避免影响数据库性能应该及时删除不再使用的索引。
alter table book drop index bookIndex;
drop index bookIndex on book;
有MyISAM,InnoDB,MEMORY,MERGE等,这里只说MyISAM和InnoDB
MyISAM和InnoDB均采用b+树的索引结构
为什么用b+树呢:
什么地方使用索引:
索引注意事项:
触发器(TRIGGER)是MySQL的数据库对象之一,该对象与编程语言中的函数非常类似,都需要声明、执行等。但是触发器的执行不是由程序调用也不是由工程师手工启动,而是由事件来触发、 激活从而得以执行。
create trigger triggerName
after triggerEvent on tableName for each row
begin
triggerSTMT
end