万字详解玩转MySQL

MySQL语法

前言

MySQL的语法虽然简单,但是内容还是比较多的,因此写上这篇文章,方便与大家一起学习,共同进步,欢迎各位大佬的批评指正错误.

数据库的分类

数据库可以分为关系型数据库非关系型数据库

关系型数据库:是指采用了关系模型来组织的数据库.相当于一个二维的表格(此处可以联想到Excel表格),常见的关系型数据库有(Oracle/MySQL/SQL Server).
非关系型数据库(NoSQL):通常值数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定.非关系型数据库存储数据的格式可以是Key- Value形式(memcached/redis),基于文档型(mongodb),基于图形(Neo4j)等等.

MySQL安装

安装包下载
文章教程

视频教程

相信各位大佬看完这些链接就能顺利安装成功MySQL.

数据库的基础操作

安装好之后我们就可以来编写SQL代码

创建数据库:

语法:

create database (数据库名)

示例:创建blog数据库

create database blog; -- blog为数据库名

注:-- 为SQL的注释
运行上述代码之后我们的数据库就创建好了,那么我们怎么样才能查看我们创建成功的数据库呢?通过下面代码就能显示已有的数据库.

显示数据库

语法:

SHOW DATABASES;

在这里插入图片描述
创建好数据库之后我们就要对数据库进行操作前,我们先要选中数据库才能对数据库进行操作,
运行下面的代码就能操作你想操作的数据库.

使用数据库

语法

use (数据库名);

示例:使用blog数据库

use bolg;

在这里插入图片描述

删除数据库

语法:

drop database (数据库名);

示例:删除blog数据库

drop database blog;

通过上述代码就能成功删除我们创建的blog数据库,但是我们在工作中要谨慎使用这个操作,不然就得准备跑路了.
请添加图片描述

SQL中的基本类型

数值类型

数据类型 大小 说明 对应的java类型
BIT(M) M指定位数默认为1 二进制数,m的范围从1到64 存储数值范围从0 - 2^m - 1. 常用Boolean对应BIT,此时默认是1位,即只能存0和1
TINYINT 1字节 Byte
SMALLINT 2字节 Short
INT 4字节 Integer
BIGINT 8字节 Long
FLOAT(M,D) 4字节 单精度,m指定长度,D指定小数位数,会发生精度丢失. Float
DOUBLE(M,D) 8字节 Double
DECIMAL(M,D) M/D最大值+2 双进度,M指定 长度,D表示小数点位数,精确数值 BigDecimal
NUMERIC(M,D) M/D最大值+2 和DECIMAL一样 BigDecimal

1.数值类型可以指定为无符号类型
2.对应的数字范围:
有符号:-2^(字节数8 - 1) 到 2 ^(字节数8 - 1) -1
无符号:0 - 2^(字节数*8) -1
3.decimal类型以时间以及空间的代价,来使表示的精度更精确.

字符串类型

数据类型 大小 说明 对应java类型 对应c类型
VARCHAR[SIZE] 0-65535字节 可变长度字符串 String char[]
TEXT 0-65535字节 长文本数据 String char[]
MEDIUMTEXT 0-16777215字节 中长度文本数据 String char[]
BLOB 0-65535字节 二进制形式的长文本数据 BYTE[] char[]

日期类型

数据类型 大小 说明 对应java类型
DATETIME 8字节 范围从1000到9999年,不会进行时区的检索及转换 java.util.Date/java.sql.Timestamp
TIMESTAMP(时间戳) 4字节 范围从1970到2038年,自动检索当前时区进行转换 java.util.Date/java.sql.Timestamp

timestamp是以1970年1月日0时0分为基准时间,截止到2038-01-19 03:14:07
timestamp的日期格式为YYYY-MM-DD HH:MM:SS

MySQL中表的操作

1)创建表

语法:

create table [表名] (列名 类型名,列名 类型名)

注意:表名不能和SQL的关键字冲突,也可以使用 (`)反引号来引用
示例: 创建一个学生表,包含学号,姓名,省份证号码,成绩.

create table student (id int,name varchar(20),chinese decimal(5,2),math decimal(5,2),english decimal(5,2));

2)查看已创建的表

语法:

show tables;
示例:显示已创建的表

show tables;

运行结果:
在这里插入图片描述

通过该语句我们可以查看我们所选中的数据库中的表.

3)查看指定表结构

语法:

desc [表名]

desc student;

运行结果:
在这里插入图片描述

4)删除表
语法:

drop table [表名]
示例:删除 student 表

drop table student;

与删除数据库相同,删除表操作的风险极大,请谨慎使用.
运行结果:
在这里插入图片描述
SQL语句使用--空格+描述 来注释

create table student (id int,name varchar(20),chinese decimal(5,2),math decimal(5,2),english decimal(5,2)); -- 我是注释

运行上述代码 – 后的代码不执行.
运行结果:
在这里插入图片描述

MySQL表的增删改查(CRUD)

新增元素(create)

语法:

insert into [表名] values ();-- 插入所有列的数据
insert into [表名] (指定的列名) values();-- 插入指定列的数据
insert into [表名] values (),(),…;-- 插入多行数据

示例1: 插入一行数据

insert into student values (1,'刘一',78.9,66.6,88.0);

运行结果:
在这里插入图片描述

示例二:只插入姓名与语数英的成绩(没有插入的列默认为null)

insert into student (name,score) values ('陈二',88.7);

在这里插入图片描述

示例三: 插入多行数据

insert into student values 
(3,'张三',89.7,52.5,76.5),
(4,'李四',99.6,79.5,89.7),
(5,'王五',71.5,99.5,88.6);

运行结果:
在这里插入图片描述

示例四:插入多行指定列数据(姓名,成绩)

insert into student (name,Chinese) values 
('赵六',66.7),
('孙七',77.7),
('周八',88.8);

运行结果:
在这里插入图片描述

查找(retrieve)

1)全列查找
语法:

select * from [表名]; (这样的查找方式仅限在测试环境中使用,切不能再生产环境中使用,否则会给生产环境的服务器造成很大的负担,甚至服务器卡死.)
示例:查看学生表中的所有列的数据

select * from student;

运行结果:
在这里插入图片描述

2)指定列查找
语法:

select [列名] from [表名];

示例:只查看姓名与成绩

select name,chinese,math,english from student;

运行结果:
在这里插入图片描述

3)查询字段为表达式
select 表达式 from 表名;
示例: 查找所有同学的姓名和总成绩

select name,chinese+math+english from student;

在这里插入图片描述
注:任何数与null球和都为null上图中后三位同学的成绩为NULL.
示例2:所有同学的语文成绩+10分

select name,chinese + 10 from student;

运行结果:
在这里插入图片描述
4)查找字段指定别名
语法

select [列名] (as) [别名] from [表名];-- 其中ask可以省略
示例: 将总成绩列名指定为total;

select name,chinese + math + english as total from student;

运行结果:
在这里插入图片描述
5)去重
语法:

select distinct [列名] from [表名];

示例:去除重复的英语成绩

select distinct english from student;

运行结果:(将成绩为null的成绩去重了)
在这里插入图片描述
6)排序
语法:

select [列名] from [表名] order by [列名] acs(升序)/desc(降序);-- 默认为升序
示例1:查找同学的信息并按照语文成绩升序

select * from student order by chinese asc;

运行结果:
在这里插入图片描述
示例2:查找同学信息并按照总成绩降序

select  * from studnt order by chinese + math + english desc;

运行结果:(其中默认NULL为最小值)
在这里插入图片描述
示例3:按照总成绩排序,使用别名

select name,chinese + math + english total from student order by total desc; 

运行结果:
在这里插入图片描述
示例4:按照多个列进行排序(先把所有同学的信息按照语文,数学,英语的顺序降序排序)

select * from student order by chinese desc,math desc,english desc;

运行结果:(当前一项相同时比较后一项)
在这里插入图片描述
7)条件查询(where)
条件查询中涉及的运算符:

运算符 说明
> 大于
>= 大于等于
< 小于
<= 小于等于
= 等于,不能比价NULL,当NULL = NULL 的结果是null
<=> 可以比较NULL,null<=>null的结果是true
!= /<> 不等于
between A and B 范围匹配[A,B],当A<= VALUE<=B,返回true
in(option,…) 如果是option中任意一个,返回ture
IS NULL 是NULL
IS NOT NULL 不是NULL
LIKE 模糊匹配.%表示任意多个(包括0个)任意字符;_表示任意一个字符
and 多个条件都为true,结果才是true
or 任意一个条件为true,结果就是true
not 条件为true,结果为false

示例1:查找math为null的记录

select * from student where math <=> null;
//select * from student where math is null;

运行结果:
在这里插入图片描述
示例2:查找数学成绩不及格的同学

select * from student where math < 60;

运行结果:
在这里插入图片描述
示例3:查找语文成绩比英语好的同学

select * from student where Chinese > english;

运行结果:
在这里插入图片描述
示例4:查找总分大于200分的数据

select name,chinese + math + english total from student where chinese + math + english > 200;

运行结果:

在这里插入图片描述
示例5:查询语文成绩大于80并且英语大于80

select * from student where Chinese > 80 and English > 80;

在这里插入图片描述
示例6:查询英语成绩大于80或者语文成绩大于80的数据.

select * from student where Chinese > 80 or English > 80;

运行结果:
在这里插入图片描述
注:当and和or同时出现是,and的优先级要更高一些,所以建议使用时适当加上括号.

示例7:查询语文成绩在[80,90]之间的数据

select * from student where Chinese  between 80 and 90;
select * from student where Chinese >= 80 and Chinese <= 90;

运行结果:
在这里插入图片描述
示例8:查询数学成绩是66.6,99.5,100的数据

select * from student where math in (66.6,99.5,100);

运行结果:
在这里插入图片描述
示例9)查找姓李的同学的数据

select * from student where name like '李%';

运行结果:
在这里插入图片描述
示例9:查找所有同学语文成绩为9开头的数据.

select * from student where Chinese like '9%';

在这里插入图片描述
8)分页查找(limit)
示例1:查找总成绩前三的同学

select name,chinese + math + english total from  student order by chinese + math + english desc limit 3;

运行结果:
在这里插入图片描述
示例2:查找同学信息总分排名为3-5名的数据

select name,chinese + math + english total from student order by total desc limit 3 offset 2;

运行结果:
在这里插入图片描述
当limit的数据大于数据的个数是被允许的此时显示的是所有数据.

select name,chinese + math + english total from student order by total desc limit 30 offset 2;

运行结果:
在这里插入图片描述
而当偏移量的数据大于数据的个数此时显示的数据就是null.

select name,chinese + math + english total from student order by total desc limit 3 offset 20;

运行结果:
在这里插入图片描述

修改(update)

语法

update [表名] set [列名] where(条件)

示例1:把张三同学的数学成绩改成50,语文成绩改成95.

update student set math = 50,Chinese = 95 where name = '张三';

运行结果:在这里插入图片描述
示例2:所有同学语文成绩-10;

update student set  Chinese = Chinese -10;

在这里插入图片描述
示例3 总成绩最后三位同学的语文成绩+ 20.

update student set Chinese= Chinese + 20  order by chinese + math + english limit 3;

在这里插入图片描述

删除操作(delete)

语法:

delete from [表名] where [筛选条件];
示例1:删除周八同学的成绩.

delete from student where name = '周八';

运行结果:
在这里插入图片描述
示例2 :删除表中全部数据

delete from student;

运行结果:
在这里插入图片描述
注:删除操作非常危险,一旦数据删除了,通常常规手段是无法恢复的,所以谨慎使用

数据库约束

1)约束类型

类型 说明
NOT NULL 指示某列不能存储NULL值
UNIQUE 保证某列的每行必须有唯一的值
DEFAULT 规定没有给列赋值时的默认值
PRIMARY KEY 是 NOT NULL 与 UNIQUE的结合,确保某列有唯一表示,有助于更容易更快速地找到表中的一个特定的记录
FOREIGN KEY 保证一个表中的数据匹配另一个表中的值的参照性完整
check 保证列中的值符合指定的条件

2)NOT NULL(非空)
指定某列不能为null.

create table student(id int not null,name varchar(20),score decimal(3,1));
insert into student values (null,'张三',99.9);
desc student;

运行结果:
在这里插入图片描述
在这里插入图片描述

由于ID指定为非空,当插入数据为null时,就会报错.
3)UNIQUE(该列的所有行不能重复)

create table student1(id int unique,name varchar(20),score decimal(3,1));
desc student1;
insert into student1 values
(1,'张三',99.9),
(1,'李四',88.8);

运行结果:
在这里插入图片描述
在这里插入图片描述

当id重复时就会报错.
4)not null 和 unique 可以同时使用,相当于PRIMARY KEY.

create table student2(id int unique not null,name varchar(20),score decimal(3,1));
create table student3(id int primary key,name varchar(20),score decimal(3,1));
desc stduent2;
desc student3;

运行结果:
在这里插入图片描述
那怎样能能保证主键不重复呢?
我们可以使用auto_increment来自动生成主键的值,来保证主键值不重复.

create table student5(id int primary key auto_increment,name varchar(20),score decimal(3,1));
desc student5;
insert into student5 values
(null,'刘一',66.6),
(null,'陈二',77.7);
select * from student5;

运行结果:
在这里插入图片描述
冲上图可以看出,在我们插入数据的时候没有给定id的值,由于设置了自动生成主键的值,自动从1开始生成主键的值.
那要是我们删除其中一个自增主键的值,这个值会不会被重新利用呢?

delete from student5 where name = '陈二';
insert into student5 values
(null,'张三',66.6);
select * from student5;

运行结果:
在这里插入图片描述
显然从运行结果我们能看出删除的自增主键值不会被重复利用.
需要注意的是,自增主键要注意不要超出数据类型的范围,否则数据会出现溢出的情况,造成严重的后果.
5)设置默认值(default)

create table student4(id int, name varchar(20) default 'unknown',score decimal(3,1));
desc student4;

运行结果;
在这里插入图片描述
6)FOREIGN KEY(外键)
语法

foreign key [需关联的列名] references [关联的类名];
示例:创建学生表student,一个学生对应一个班级,一个班级对应多个学生。使用id为主键,classes_id为外键,关联班级表id.

create table class (id int primary key auto_increment,name varchar(20),`desc` varchar(100));
create table student (id int primary key auto_increment,name varchar(20),classes_id int, foreign key (classes_id) references class(id));
insert into class values 
(null,'1班','年级排名第1'),
(null,'2班','年级排名第2');
select * from class;
insert into student values
(1,'刘一',1),
(2,'陈二',2),
(3,'张三',3);
select * from student;

运行结果:
在这里插入图片描述
上述代码中class为父表,student为子表,用父表来限制子表,要求子表的数据得在父表中存在.
这里也要求子表中设置foreign key的时候,关联父表的列,需要带上primary key 或者unique.

数据库的设计

1)1对1
每个人与它的身份证就是一一对应的关系的关系.
只需一个表就能描述这种情况.

个人信息/身份证信息(个人id,个人姓名,…,身份证号);

2)1对多
学生与班级之间的关系;一个学生可以属于一个班级,而一个班级可以包含多名学生.
方式1:
班级表:

班级id 班级名称 学生id
1 1班 1,2
2 2班 3

学生表:

学号 姓名
1 刘一
2 陈二
3 张三

方式2:
学生表:

学号 姓名 班级id
1 刘一 1
2 陈二 1
3 张三 2

班级表:

班级id 班级名字
1 1班
2 2班

3)多对多
学生 课程 一个学生可以选择多个课程;一个课程也可以被多个同学选择.
需要引入一个中间表

学生表:

学号 姓名
1 刘一
2 陈二
3 张三

课程表:

课程id 课程名
1 语文
2 数学
3 英语

中间表:学生/课程表

学号 课程id 说明
1 1 刘一选了语文
1 2 刘一选了数学
2 2 陈二选了数学
2 3 陈二选了英语
3 1 张三选了英语

插入查询结果

语法:

INSERT INTO TABLE_NAME (需插入的指定列) select 插入的指定列 from [插入数据的表名];

示例:构建user1表和user2表,其中user1为:

id name description
1 刘一 学神
2 陈二 学霸
3 张三 法外狂徒

将user1表中的name,description,列的信息插入user2表中

create table user1 (id int primary key auto_increment,name varchar(20),description varchar(100));
insert into user1 values
(1,'刘一','学神'),
(2,'陈二','学霸'),
(3,'张三','法外狂徒');

create table user2(id int primary key auto_increment,name varchar(20),description varchar(100),interesting varchar(50));
insert into user2  (name, description) select name,description from user1;
select * from user2;

运行结果:
在这里插入图片描述

聚合查询

聚合函数

函数 说明
count(列名) 返回查询到的数据的数量(不计算NULL的值)
sum(列名) 返回查询到的数据的总和,不是数据没有意义
AVG(列名) 返回查询到的数据的平均值,不是数据没有意义
MAX(列名) 返回查询到的数据的最大值,不是数据没有意义
MIN(列名) 返回查询到的数据的最小值,不是数据没有意义

count

示例:统计学生人数

create table student(id int primary key auto_increment,name varchar(20),chinese decimal(3,1),math decimal(3,1), english decimal(3,1));

insert into student values
(null,'刘一',99.9,98.7,96.5),
(null,'陈二',88.9,87.6,88.8),
(null,'张三',66.5,54.2,60.1),
(null,'李四',null,74.6,56.9);
select * from student5;
select count(*) from student;

运行结果:

在这里插入图片描述
实例2 : 查询参加语文考试的人数

select count(chinese) from student;

运行结果:我们可以从结果中看出,当值为null时,不统计
在这里插入图片描述

SUM

示例:求所有同学的数学成绩和

select sum(math) from student;

运行结果:
在这里插入图片描述

AVG

示例:求学生的平均数学成绩

select avg(math) from student;

运行结果;
在这里插入图片描述

MAX

示例: 求最高的数学成绩

select max(math) from student;

运行结果:
在这里插入图片描述

MIN

示例:求最低的数学成绩

select min(math) from student;

运行结果:
在这里插入图片描述

GROUP BY字句

select 中使用GROUP BY字句可以对指定列进行分组查询.需满足条件:使用group by进行分组查询时,select指定的字段必须是"分组依据字段",其他字段若想出现在select中则必须包含在聚合函数中.
语法:

select 列名… from 表名 group by 需要被分组的列名;

示例:根据成绩等级分组
学生表:

id name score score grade
1 刘一 95 优秀
2 陈二 90 优秀
3 张三 50 不及格
4 李四 80 良好
5 王五 85 良好
6 赵六 60 及格
7 孙七 75 及格
8 周八 40 不及格
create table student (id int primary key auto_increment,name varchar(20),score decimal(3,1),score_grade varchar(10));

insert into student values
(null,'刘一',95,'优秀'),
(null,'陈二',90,'优秀'),
(null,'张三',50,'不及格'),
(null,'李四',80,'良好'),
(null,'王五',85,'良好'),
(null,'赵六',60,'及格'),
(null,'孙七',75,'及格'),
(null,'周八',40,'不及格');

select score_grade from student group by score_grade;

运行结果:

在这里插入图片描述
示例: 求不同等级的平均成绩

select score_grade,avg(score) from student group by score_grade;

运行结果:
在这里插入图片描述
示例3:查询各个等级成绩的平均值,和,最大值,最小值

 select score_grade as grade,avg(score) as average,max(score) as maxValues,min(score)as  minValues,sum(score) as sumValues from student group by score_grade;
 

运行结果:
在这里插入图片描述

HAVING

GROUP BY 进行分组后,需要对分组结果在进行条件过滤时,不能使用where语句,而需要用having
示例:显示平均成绩大于或等于70分的成绩等级和平均成绩

select score_grade,avg(score) from student group by score_grade having avg(score) > 70;

运行结果:
在这里插入图片描述

联合查询

在实际开发中往往数据来自不同的表,所以需要多表联合查询.

笛卡尔积

多表查询需要先对多张表进行笛卡尔积:

测试表1:学生表:

id name course_id
1 刘一 1
2 陈二 2
3 张三 4
id name
1 语文
2 数学
3 英语
4 物理

计算他们的笛卡尔积的结果是:

create table course (id int primary key auto_increment,name varchar(20));
insert into course (name) values
('语文'),
('数学'),
('英语'),
('物理');
create table student (id int primary key auto_increment,name varchar(20),course_id int,foreign key (course_id) references course(id));
insert into student (name,course_id) values
('刘一',1),
('陈二',2),
('张三',4);

select * from student ,course;

笛卡尔积的结果:
在这里插入图片描述

测试表:

班级表

id name description
1 2101班 学习了语文数学英语
2 2102班 学习了物理
3 2103班 学习了化学

学生表

id sn name mail classes_id
1 0001 刘一 [email protected] 1
2 0002 陈二 null 1
3 0003 张三 null 1
4 0004 李四 [email protected] 1
5 0005 王五 null 1
6 0006 赵六 [email protected] 2
7 0007 孙七 null 2
8 0008 周八 [email protected] 2

课程表:

id name
1 语文
2 数学
3 英语
4 物理
5 化学
6 生物

分数表

id score student_id course_id
1 70.5 1 1
2 98.5 1 3
3 33 1 5
4 98 1 6
5 60 2 1
6 59.5 2 5
7 33 3 1
8 68 3 3
9 99 3 5
10 67 4 1
11 23 4 3
12 56 4 5
13 72 4 6
14 81 5 1
15 37 5 5
16 56 6 2
17 43 6 4
18 79 6 6
19 80 7 2
20 92 7 6
create table classes (id int primary key auto_increment,name varchar(20),description varchar(100));
insert into classes (name,description) values
('2101班','学习了语文/数学/英语'),
('2102班','学习了物理'),
('2103班','学习了化学');

create table students (id int primary key auto_increment,sn varchar(10),name varchar(20),mail varchar(20),classes_id int,foreign key (classes_id) references classes(id));
insert into students (sn,name,mail,classes_id) values
('0001','刘一','[email protected]',1),
('0002','陈二',null,1),
('0003','张三',null,1),
('0004','李四','[email protected]',1),
('0005','王五',null,1),
('0006','赵六','[email protected]',2),
('0007','孙七',null,2),
('0008','周八','[email protected]',2);

create table courses (id int primary key auto_increment,name varchar(20));
insert into courses (name) values
('语文'),
('数学'),
('英语'),
('物理'),
('化学'),
('生物');

create table scores (id int primary key auto_increment,score decimal(3,1),student_id int,course_id int, foreign key (student_id) references students(id),foreign key (course_id) references courses(id));
insert into scores (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);

内连接

语法:

1)select 字段 from 表1 别名 [inner] join 表2 别名2 on链接条件 and 其他条件
2)select 字段 from 表1 别名1,表2 别名2 where 链接条件 and 其他条件

示例:查询李四同学的成绩

select name,course_id,score from scores,students;-- 笛卡尔积
select name,course_id,score from scores,students where scores.student_id = students.id;-- 选出有效的数据
select name,course_id,score from scores,students where scores.student_id = students.id and name = '李四';-- 从有效数据中选出李四的成绩

笛卡尔积结果:
在这里插入图片描述
选出有效数据:
在这里插入图片描述

从有效成绩中选出李四同学的成绩.
在这里插入图片描述
示例:查询所有同学的总成绩,以及同学的个人信息

select students.sn sn,students.name name,students.mail mail,students.classes_id classes_id, sum(score) score from scores,students  where students.id = scores.student_id  group by students.id;

运行结果:
在这里插入图片描述
示例3:查找所有同学的每一科成绩,和相关信息

select students.name student_name,courses.name course_name,scores.score from students,scores,courses where students.id = scores.student_id and courses.id = scores.course_id; -- 方法1
select students.name student_name,courses.name course_name,scores.score from students join score scores on scores.student_id = students.id join course courses on scores.course_id = courses.id;

运行结果:(查出来的都是有成绩的同学,而周八同学的成绩并没有显示)

在这里插入图片描述

外连接

外连接分为左外连接和右外连接.如果联合查询,左侧的表完全显示我们左外连接,右侧表完全显示就是右外连接.
语法:

select 字段名 from 表1 left join 表2 on 连接条件;
select 字段名 from 表1 right join 表2 on 连接条件;

select * from students left join scores on students.id = scores.student_id;-- 左连接 周八同学的信息就显示出来了 
select * from scores right join students on  students.id = scores.student_id;-- 右外连接

运行结果:
在这里插入图片描述
详解内连接与外连接的区别

自连接

自连接是指同一张表连接自身进行查询.
示例:显示所有语文成绩比英语成绩低的成绩信息

--方式1:
-- 找到语文与数学的id
select id,name from courses where name = '语文' or name = '英语';

select * from scores s1,scores s2 where s1.student_id = s2.student_id and s1.score < s2.score and s1.course_id = 1 and s2.course_id = 3;

-- 方式2
select students.*,s1.score 语文 s2.score 英语 from scores s1 join scores s2 on s1.student_id = s2.student_id join students on s1.student_id = students.id join courses c1 on s1.course_id = c1.id join courses c2 on s2.course_id = c2.id and s1.score < s2.score and c1.name = '语文' and c2.name = '英语';

运行结果:
在这里插入图片描述
在这里插入图片描述

子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询
单行子查询
示例:查找刘一同学的同班同学

select students.name name from students where students.classes_id = (select classes_id from students where name = '刘一');

运行结果:
在这里插入图片描述
多行子查询
示例:查询语文或英语课程的成绩

select * from scores where course_id in (select id from courses where name = '语文' or name = '英语');

运行结果
在这里插入图片描述

合并查询

在实际应用中,为例合并多个select的执行结果,可以使用集合操作符union,union all.
示例:查询 id 小于3 ,或则名字为’生物’的课程

select * from courses where id < 3 union select * from courses where name = '生物';
-- 当然这可以使用or实现

运行结果:(union会自动去掉结果集中重复行)
在这里插入图片描述
若不想去掉结果集中的重复行,使用 union all
示例:查询id < =3 或者名字为’英语’的课程

select * from courses where id <= 3 union all select * from courses where name = '英语';

运行结果:
在这里插入图片描述

索引与事务

索引(index)

什么索引

索引是一种特殊的文件,包含着对数据表里所记录的引用指针,可以对表中的一列或多列创建索引,并指定索引的类型,各类索引有各自的数据结构实现

索引的作用

1)数据库中标/数据/索引之间的关系,类似于书/书的内容/书的目录的关系
2)索引所起的作用也类似于目录,可以用于快速定位和检索数据(为了避免数据库进行顺序表查找,加快查找的效率,但是会减慢插入和删除,修改的效率)
3)索引对于提高数据库的性能有很大的帮助.
4)索引会占用空间(本质上也是使用空间换去时间)

索引的使用场景

索引的使用场景是,数据量大,且经常对这些列进行条件查询.而其他的插入/删除/修改频率比较低.

索引的底层数据结构

索引可以考虑的数据结构:
1.二叉搜索树的查找效率是O(logN)
二叉搜索树的缺点:如果数据量太大,二叉树的高度就会很高,查询速度还是会很慢;
二叉树的每个节点只存储一个记录,一次查询在树上找的时候会花费磁盘IO次数较多;
获取中序遍历的效率为O(N),导致范围查找效率也比较低效.

二叉搜索树内部是有序的(中序遍历有序O(N)),所以可以处理范围性的查找,但是查找的效率比较低.(二叉搜索树的节点最多两个叉,当数据量大的时候,树的高度比较高,最终的操作效率也会降低)
2.哈希表 查找效率是O(1)
由于哈希表的查找效率高可以使用哈希,但是哈希表只能处理相等的情况不能处理其他的逻辑,所以数据库底层不能使用哈希表.

索引的数据结构是一种N叉搜索树(B+树)

B-树

在介绍B+树之前先介绍一下B-树
请添加图片描述

B-树与二叉搜索树的差别:
1.每个节点是N叉;
2.每个节点存储多个数据;
3.每个节点度 = 存的数据 + 1;

上图中4|8节点把数据集合分为了3个部分:1)小于4;2)在4-8之间3)大于8,可以看出在B树上的查找是N分查找,效率高.而且每个节点存了多个数据,每个节点又有多个度,与二叉树相比,保存相同个数的元素时,B树的高度就会低;处理范围查找效率也会更高.

B+树(真实的索引底层结构)

与B树相比,主要是两个地方发生了变换
1.每一层的元素之间都链接到了一起
2.数据只在叶子节点,非叶子节点上只保存一些辅助查找的边界信息.
请添加图片描述
B+树的优点:
任然是N叉树,层级小,非叶子节点不在存储数据,数据只存储在同一层的叶子节点上,所以B+树从根节点到每一个叶子节点的路径都是一样长的.
2.叶子之间,增加了链表,所获取所有节点,不在需要中序遍历,使用链表遍历就可以快速访问到.
3.范围查找方面,当定位到min与max时,中间叶子节点就是结果集,不需要中序回溯(这是B+树比B树的最大优势)
4.叶子节点存储实际记录行,记录行相对比较紧密的存储,适合大数据量磁盘存储;非叶子节点存储记录的PK,用于查询加速,适合内存存储.
4.非叶子节点,不存储实际记录,而只存储记录的KEY的话,那么在相同的内存的情况下,B+树能够存储更多索引.

索引的使用

加在主键上的索引和其他列的索引是不相同的;主键索引的叶子节点存储的是数据的完整记录,其他索引的叶子节点存的是主键的id,所以其他列的索引会再根据主键id去主键索引中查找完整的记录(这个过程被称为回表).
查看索引
语法:

show index from [表名];

show index from students;

运行结果
在这里插入图片描述

创建索引
语法:

create index 索引名 on 表名(字段名);

 create index index_name_student on students(name);

运行结果:
在这里插入图片描述
删除索引
语法:

drop index 索引名 on 表名;

drop index index_name_student on students;

运行结果:(主键索引不能被删除)数据库中的数据就是主键索引的B+树组织的.
创建和删除索引是非常耗时的操作,所以尽量避免在线上进行这些操作.
在这里插入图片描述
使用explain语句可以分析SQL的执行过程,能够看到是否使用了索引.

事务

事务的作用,解决的问题

转账的问题:假设甲要向乙转账10000.
这个过程可以分为两步:第一步:甲的账户-10000 第二步:乙的账户+10000;
如果第一步执行成功了,执行第二步出了问题,此时甲的前减少了乙的钱没有增加,所以钱就会凭空消失了.事务就是为了解决这个问题.
什么是事务?
把一组操作封装在一起,称为一个共同的执行单元.此时执行整个事务就能避免以上的问题.

事务的特点

1.原子性:事务中的若干个操作,要么全部执行成功,要不就全部不执行(这里不是不执行,而是一旦中间某个步骤执行出错了,就把前面已经执行完毕的步骤回滚(rollback)回去)
2.一致性:执行事务前后,数据始终处于一种合法的状态.例如:转账操作,减账户余额的时候,账户余额不能为负.
3.持久性:事务一旦执行完毕,此时对于数据的修改就是持久生效的(存入磁盘).
4.隔离性:涉及到"并发执行事务".

事务的使用

语法:

start transaction; 
-- 语句;
 commit;

MySQL JDBC编程

JDBC(java Database Connectivity),java数据库链接.是一种用于执行SQL语句的的java API,它是java中的数据库连接规范.这个API由java.sql*,javax.sql.*包中的一些类和接口组成,它为java开发人员操作数据库提供了一个标准的API,可以为多重关系数据库提供统一访问.

JDBC的使用

准备数据库驱动包

1.在项目中创建一个目录,并将mysql-connector-java-5.1.47.jar复制到该目录中.
2.配置项目的属性,让项目能够找到jar包.
在这里插入图片描述

JDBC编程步骤

1.创建DataSourse对象
2.基于DataSourse对象,创建Connectiond对象,和数据库建立连接(相当于打开客户端输入了密码,连接成功了)
3.PrepareStatement对象拼装具体的SQL语句(客户端输入SQL的过程)
4.拼装好SQL之后,需要执行SQL;(客户端中敲下回车,此时SQL就被发送到服务器了)
5.查看服务器返回的结果(客户端显示出的结果)
6.关闭连接,释放资源(退出客户端)

public static void main(String[] args) throws SQLException {
    
    
        //1.创建DataSource对象(用于配置如何连接MySQL),它的生命周期应该是跟随整个程序
        DataSource dataSource = new MysqlDataSource();
        //接下来需要配置URL,User,Password ,需要对dataSource进行向下转型
  // 向下转型 需要指定访问哪个数据库服务器中的数据库   协议名       ip地址    端口号(为了区分一台主机的多个服务器)
        ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java_1124?characterEncoding=utf-8");
        //                                                                 要访问的数据库名  编码格式UTF-8
        ((MysqlDataSource)dataSource).setUser("root");//用户名默认为root
        ((MysqlDataSource)dataSource).setPassword("----");//为登录密码

        //2.Connection(表示建立好的一次连接)建立连接,建立连接的意义是为了验证当前的网络通信是否正常,如果不正常就会抛出SQLExcepion异常,
        //connection对象生命周期应该是比较短的,每个请求创建一个新的连接
        Connection connection = dataSource.getConnection();


        //3.拼接SQL语句,用到PrepareStatement对象
        //方式1
//        //String sql = "insert into student values(1,刘一,2)";//方式一;也可以动态的拼接进去
//        PreparedStatement statement = connection.prepareStatement(sql);
        //方式二:动态拼接
        int id = 1;
        String name = "刘一";
        int class_id = 2;
        String sql = "insert into student values(?,?,?)";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setInt(1,id);//1为第一个? 1/2/3为?的下标
        statement.setString(2,name);
        statement.setInt(3,class_id);

        //4.拼装好了之后,就可以执行SQL了
        // insert delete update 都使用executeUpdate方法来执行
        // select 使用 executeQuery来执行
        //返回值表示此次操作修改了多行.当返回值大于1时就操作成功了
        int ret = statement.executeUpdate();
        System.out.println("ret :" + ret);
        
        //执行完毕后,需要关闭释放相关资源
        statement.close();
        connection.close();
    }

运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/529edbd4dfc6424795a69d828f8ed6a1.png)
其中ret = 1表示执行成功了,我们可以从客户端中去查看插入的数据

```sql
select * from student;

在这里插入图片描述
显然我们插入数据成功了,在java中执行其他的操作也和上述代码步骤一致,只有查询操作时的返回值为ResultSet集合,所以要查看执行结果是需要while循环变量打印,代码实现如下

public static void main(String[] args) throws SQLException {
    
    
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java_1124?characterEncoding=utf-8");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("xcb@19980521");

        Connection connection =dataSource.getConnection();

        String sql = "select * from student";

        PreparedStatement statement = connection.prepareStatement(sql);
        //循环遍历
        ResultSet resultSet = statement.executeQuery();
        while (resultSet.next()){
    
    
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            int class_id = resultSet.getInt("class_id");
            System.out.println("id: " +id + " name: " + name + " class_id: " + class_id );
        }
        resultSet.close();
        statement.close();
        connection.close();
  }

执行结果:
在这里插入图片描述

MySQL总结

请添加图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41098429/article/details/121435534