数据库

Posted 李憨憨_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库相关的知识,希望对你有一定的参考价值。

数据库


文章目录


增删改查进阶

聚合函数,分组查询,键值约束,表的设计,多表联查
  聚合函数:mysql中内部定义的一些数据统计函数
    统计结果的条数:count(*);
    统计指定列总和:sum(fields);
    统计指定列最大:max(fields);
    统计指定列最小:min(fields);
    统计指定列平均:avg(fields);
  分组查询:以指定列为依据对数据库的数据进行分组,并且可以使用聚合函数进行数据统计—group by fields…
    分组查询字段中只能有分组依据字段以及聚合函数(分组之后,一个分组中有很多成员)
    select distinct role, avg(salary) from emp group by role;
    分组查询中,条件过滤不能使用where,而是使用having
    select role, avg(salary) from emp group by role having avg(salary)>1500;
  表中的字段约束:都是在创建表的时候,对指定字段的数据约束
    非空约束:not null;
      约束表中指定字段数据不能为null
    唯一约束:unique/unique key
      约束表中指定字段数不能重复,必须唯一
    主键约束:primary key
      约束表中指定字段非空且唯一,但是一张表只能有一个主键
    外键约束:foreign key … references…
      约束表中指定字段的数据,必须受限于父表中的指定字段—添加的数据必须在父表中存在;
      假设一个学生班级是一年级一班,班级表中必须有一年级一班;在班级表中有了指定班级,学生信息中才能添加班级信息
    默认值:default
      给指定字段设置一个默认值,当指定字段不能插入数据时则使用默认值填充
    自增属性: auto_increment
      在整形数据字段,每次添加的数据自动+1,只能用于主键字段
    check子句:check(sex=‘男’ or sex=‘女’)
      对指定字段进行规则校验,符合规则则执行,不符合则报错; mysql中可以使用,但不生效

    组合主键:primary key-约束字段非空且唯一,一张表中只能有一个主键
      以多个字段的整体作为主键

数据库表的设计:ER关系图,三大范式

ER关系图:


  一对一:一个实体有一个对应信息
  多对一:多个实体属于另一个实体
    学生信息表中就需要包含班级id
  多对多:

    一个学生可以学习多个课程
    一门课程可以被多个学生学习
    通常需要创建一个中间表来建立两个实体的关系
    学生与课程通过学生课程表关联
  ER图—实体联系图,作用就是通过模型描述实体之间的关系,通过关系设计数据库表,以及表之间的关联

三大范式

数据库表的设计规范,遵循这些规范可以让数据库表设计的更加合理,查询效率更高
  1nf:一张表中,每个字段都必须是不可分割的原子字段

    1.当字段是费原子字段时,则进行详细查询时效率较低(只能使用模糊匹配)
    2. 其他范式的基础就是第一范式,第一范式若不遵守其他范式也没有意义
  2nf:表中每个字段必须完全与主键关联,不能不分关联

    1. 若表中字段只与主键部分关联,则在表中容易出现大量冗余数据

  3nf:表中每个字段必须与主键直接关联,而不能间接关联

    一旦表中字段与主键是间接关联,意味着这些信息与主键没有太大关系,则也可能会造成大量冗余数据

多表联查

将多张表中的数据合并到一起进行查询

笛卡尔积:将一张表中的数据逐个与另一张表中的所有数据逐个合并
  表的连接:
    内连接:[inner] join … on …,将两张表合并取过滤交集
      select a.id, a.name, b.id, b.name, from a inner join b;
      将两张表数据进行合并,ab表中不符合合并条件的数据都不要

    外连接:left/right join on
      seclect a.id, a.name, b.id, b.name from a left join b on a.id=b.id;
      seclect a.id, a.name, b.id, b.name from a right join b on a.id=b.id;
      以两张表中左表或者右表作为基表,在另一张表中查找符合条件的数据进行合并,如果找不着符合条件的,则以NULL进行连接,也就是说无论如何基表中的数据总是要全部查询

例:

创建班级表:
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)
);

ER图

初始化数据

班级信息:
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','黑旋风李逵','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); 





查看许仙同学的成绩:
  1. 通过许仙找到许仙同学的id;2. 通过许仙id在成绩表中查询成绩;

select id from student where name="许仙";
select score from score where student_id=4;
select student.name, score.score from student join score on score.student_id=student.name="许仙";


  2. 查询所有同学的总成绩,及同学的个人信息:

select id, name, qq_mail from student;
每个同学的成绩
select student_id, sum(score) from score group by student_id;
先将学生表与成绩表连接,每个学生与自己的成绩进行合并连接,接下来以学生id进行分组统计
select student.id, student.name, student.qq_mail, sum(score.score) from student join score on student.id=score.student_id group by score.student_id;

    自连接:自己连接自己
      1. 显示所有“计算机原理”成绩比“Java”成绩高的成绩信息
      ; ; 课程表1连接成绩表1,得到计算机原理的成绩表,课程表2连接成绩表2,得到Java成绩表,在他们同属于同一个同学情况进行比较

select score_java.student_id, score_computer.student_id score_java.score as java, score_computer.score as computer from score as score_java join course as course_java on score_java.student_id=score_computer.student_id and course_java,id=score_java.course.java.name="Java" join score as score_computer join course as course_computer on course_computer.id=score_computer.course_id and course_computer.name="计算机原理" and score_java.score<score_computer.score;

子查询

也叫嵌套查询
  当前sql语句的条件依赖另一个sql语句的查询结果

in与exists的区别:
  in是一个子集判断:相当于先获取子查询结果集,然后前边的sql将每一条结果在子集中进行判断,存在于子集中则获取
  exists是一个条件判读:相当于先获取前边sql的数据,判断是否符合条件,条件真假就是子查询是否有结果
  in适合于前边数据多,子查询结果集较少的场景;exists适合于子查询结果集较多的场景

合并查询

将两条sql语句的查询结果合并在一起进行返回(只是合并返回数据,并不会进行数据的连接)

索引与事务

索引:

是数据库中针对海量数据通过特定的一些数据结构所组织的数据目录,通过索引这个目录可以大大提高查询效率
数据库索引的类型:聚簇索引,非聚簇索引
  聚簇索引:索引与数据在物理存储上保持有序  一张表中只能有一个
    通常以主键构建聚簇索引,索引与数据保持物理有序,对于范围查询效率较高,但是中间插入的时候比较麻烦,重新构建索引以及数据存储的构建
在聚簇索引中,其他项的索引都是辅助索引,依然采用B+树,但是数据存储的是主键索引的值
根据辅助索引查找主键索引的数据,根据主键索引的数据查找数据实际存储
  非聚簇索引:索引保持有序,实际物理存储不一定有序
    索引有序,但数据物理存储不一定有序,索引中保存数据地址即可,在插入的时候比较灵活,数据往后存储即可,只需要重新构建索引就行,虽然插入灵活,但是范围查询效率是没有聚簇索引高的
主键索引与其他辅助索引并没有什么区别,索引项中存放的都是数据的存储地址
索引的操作:
  查看索引:show index from tb_name
  创建索引:
    1. 通过主键,唯一键,外键创建索引,这三个键值在约束字段的同时也会同步自动创建索引
    2. 创建普通索引: create index key_name on tb_name(fields);
    3. 删除索引:drop index key_name on tb_name;
索引的创建原则:
  不是所有的字段都适合创建索引,索引也不是越多越好
  频繁修改的字段不适合创建索引
  不是常用于查询条件的依赖字段不适合做索引(通常不会出现在where中的字段)
  唯一性太差的字段不适合单独做索引

事务:

一个或一组sql语句的组合所组成的执行单元
  特性:ACID
    原子性:原子操作,一个事务中的sql语句要么全部完成,要么就一个都不做
    一致性:系统总是在一个操作中从一个稳定状态到达另一个稳定状态,说白了就是操作结果是否符合预期—依赖于原子性的
    隔离性:针对并发操作而提出的,在并发操作中不会出现数据异常
    持久性:数据的持久化存储
事务的基本操作:
  开始事务:start transaction; / begin
  保存回滚点:savepoint pos_name;
  事务回滚:rollback / rollback to pos_name;
  提交事务:commit; 事务一旦提交就会持久化存储,将无法回滚
隔离性:
  如果没有隔离性在并发操作中有可能会出现什么问题
    1. 脏读:在当前事务中,读取到了另一个事务没有提交的数据
      事务A修改了数据,在还没有提交事务之间,事务B查询到了事务A修改的数据
    2. 不可重复读:在一个事务中的不同时间段读取出来的数据是不一致的。
      事务A先读取了一次数据,事务B修改了数据,并提交事务,事务A再次重新读取数据
    3. 幻读:在一个事务中的不同阶段,相同的查询得到的结果条数不同
      事务A查询结果条数有5条,事务B添加了一条数据,并提交事务,事务A重新查询则得到6条数据
  mysql中提供的隔离级别:
    读未提交:没有任何控制
    读提交:仅读取事务提交的数据—解决脏读
    可重复读:解决读未提交与幻读
    串行:一个一个进行,效率低但安全度高

以上是关于数据库的主要内容,如果未能解决你的问题,请参考以下文章

Servlet连接数据库查询班级及相应班级学生

怎么用JAVA编写一个班级管理系统

Django 练习班级管理系统二 -- 添加班级数据

sql中触发器当修改学生班级信息时自动修改相应班级的学生人数

根据班级内容创建子班级

SQL 外键名称问题