目录
我们把数据库比做成一个仓库,数据库中的表比作仓库中的货架,我们对一个数据库中的一个货架进行增删查改数据的操作就是本章要讲解的内容。
一、新增数据
在数据库中的一个表中增添数据并不是随意的,我们之前在创建表的时候规定过表中可以容纳几列数据,每列数据的类型,我们要根据可以容纳几列数据,每列数据的类型来进行新增数据的操作。
在创建表的初期所决定的数据类型是决定整张表数据类型的基础 ,新增数据的基础是创建表的时候所决定的数据类型。
我们首先创建一个person数据库,里面的student表中有学生id和学生的姓名,以及语数英成绩。
create database person charset utf8;
use person;
create table student (id int, name varchar(20),math double, english double, chinese double);
在学习插入之前我们先看一下表的结构
这是表的结构,Field就是你自己创建的列的名字,Type是每一列的类型,NULL代表的是是否允许是空的,NO代表不能不赋值,YES代表可以赋值空,Key代表者索引类型,这个我们会在后面会讲。Default是不赋值时的默认值,Extra是扩容。
(1)单行数据全列输入
单行的输入数据,把表中一行全部填满,全列输入的意思就是把id 和 name 全部填满。
插入数据我们要用insert into 表名 values (数据);这一结构进行插入。
insert into student values(1,'李四',78.56,89.56,45.67);
(2)指定列插入
我们还可以指定列进行插入
insert into student(id,name) values(2,'张三');
此次插入是把学生id和名字插入,但是没有进行成绩的输入,所以就会自动替换成默认值。这就是指定列插入。
(3)多行插入
多行插入能一次性的插入多个列。
insert into student values (3,'王五',90.32,56.23,45.23),(4,'周六',89.45,98.56,95.23);
二、简单查询数据
查询操作是我们对数据库进行的最多的操作,我们使用数据库百分之九十都是用来查询数据库。
(1)全列查询
顾名思义,就是把表中的所有数据的所有列全部查询,也就是把表中的信息全部显示出来。
select * from student;
全列查询其实是一个比较危险的操作,我们练习使用的数据库数据量通常很小,全列查询不会造成什么影响,但是如果是生产环境数据库,就不能轻易的全列查询。生产环境数据库的数据量都是非常大的,我们数据库是客户端通过网络给服务器发送请求的,通过网络来链接,如果进行全列查询,海量的数据很可能把网络的带宽吃满,网络带宽都让全列查询语句占满了,别人就不能访问数据库了,就会造成一些不必要的麻烦,所以查询的时候我们通常会加一些限制条件,这些后面会细讲。
(2)指定列查询
指定列查询相对于全列查询而言,单独列出了几个待查询的列,我们只查询这些列,就会显示出这些列的信息。
比如,以下是查询所有同学的学生id,名字和数学成绩
select id , name, math from student;
(3)查询的字段是表达式
我们在现实生活中会遇到这种的情况,我们已经有了同学们的所有的成绩,但是我们还想直到所有同学的语数英成绩的总和是多少,这时我们就需要进行表达式查询。
select id , name , math + chinese + english as total from student;
我们此次查询查了三个,一个是学生的id和name,还有一个是表达式查询,as之前的是表达式,算的就是总分,as之后的是把成绩的总合重新起个名字,查询的时候把total当成总成绩输出。
我们还可以将数据进行伪变化。
select id , name , math + 10 as total from student;
之所以是伪改变, 是因为查询操作不会改变数据库原来的数值,显示出来的只是查询的数值,并不会改变硬盘的存储值,这个大家不要担心。
(4)去重操作distinct
当数据相同的时候进行整合,我们要和之后学习的grop by来区分开。
我们在进行去重操作之前先再插入几个数据。
insert into student values(5,'周一',89.45,98.56,45.23);
insert into student values(6,'周二',78.56,89.56,45.12);
我们接下来查询数学成绩的分布,这就需要去重
select distinct math from student;
(5)排序操作 order by + 列名
排序分为升序排序和降序排序,分别用关键词 ASC 和DESC。
按照降序排序查询同学的数学成绩排名:
select id , name from student order by math desc;
我们还可以结合字段表达式进行查询
select id, name , math + chinese + english as total from student order by math + chinese + english desc;
(6)条件查询where
条件查询就是筛选条件,前面提到过全列查询的危险性,我们避免查询过量的数据,就需要通过加一些条件进行筛选,避免查询到不需要的信息,只查询我们需要的信息。
我们首先来看一下条件查询的字符集
运算符 | 说明 |
>, >=, <, <= | 大于,大于等于,小于,小于等于 |
= | 等于,NULL 不安全,例如 NULL = NULL 的结果是 NULL |
<=> | 等于,NULL 安全,例如 NULL <=> NULL 的结果是 TRUE(1) |
!=, <> | 不等于 |
BETWEEN a0 AND a1 | 范围匹配,[a0, a1],如果 a0 <= value <= a1,返回 TRUE(1) |
IN (option, ...) | 如果是 option 中的任意一个,返回 TRUE(1) |
IS NULL | 是 NULL |
IS NOT NULL | 不是 NULL |
LIKE | 模糊匹配。% 表示任意多个(包括 0 个)任意字符;_ 表示任意一个字 符 |
运算符 | 说明 |
AND | 多个条件必须都为 TRUE(1),结果才是 TRUE(1) |
OR | 任意一个条件为 TRUE(1), 结果为 TRUE(1) |
NOT | 条件为 TRUE(1),结果为 FALSE(0) |
特别需要说明的是,’=‘在数据库中即可以判断相等,也可以进行赋值操作。
’=‘和’<=>‘的区别在于是否可以比较null,前者对于null不安全的意思是null=null是不能返回true的,只会返回null,后者可以比较null是否相等的情况。
接下来我们用几个例子来进行解释:
eq1:查询数学和语文总成绩大于150的同学的名字:
select name , math + chinese as total from student where math + chinese > 150;
eq2:查询数学成绩和英语成绩的和大于100小于150的同学的名字:
有两种方法:
一种是用between and,另一种就是通过判断。
select name , math + english as total from student where math + english between 100 and 150;
select name , math + english as total from student where math + english >= 100 and math + english <= 150;
以上的都是范围查询,当我们需要查找几个固定的值得时候需要用到in。
select name ,math from student where math in (78.56,90.32);
like是一个重点,起名为模糊查询
我们先加几个孙姓同学的信息
insert into student values(7,'孙权',78.23,65.09,56.23);
insert into student values(8,'孙策',89.23,85.12,82.12);
insert into student values(9,'孙坚',84.23,72.12,65.23);
insert into student values(7,'孙权策',78.23,65.09,56.23);
insert into student values(8,'孙策坚',89.23,85.12,82.12);
insert into student values(9,'孙坚权',84.23,72.12,65.23);
’%‘是任意字符,'_'代表的是单独的字符
我们使用模糊匹配来进行查询
select name from student where name like '孙%';
select name from student where name like '孙_';
(7)分页查询limit
分页查询是把海量的数据分出不同的页,每一页有若干的数据
关键词:limit a offset b 从 b 开始,筛选a条记录
三、进阶查询数据
(1)约束类型
not null:表示指定的列不能赋予空值
unique:表示规定的某列的每一行都不能进行重复赋值的操作
default:规定给没有赋值的列指定一个默认的值
primary key:相当于not null和unique的集合,指定的列不能赋予空值并且不能有重复的数值
foreign key:外键,表示一个表中的数据匹配另一个表中的数据的值,参照完整性
1、not null:
我们新建一个class表,其中的班级一列我们设置不能赋予空值,也就是不能什么也不输入,当我们输入一个null的时候MySQL数据库就会报错。
create table class (classid varchar(20) not null, count int);
insert into class values( null, 40);
2、unique:
我们将上次创建的class表删除,重新创建一个,将classid设置成不可重复(unique)的约束条件。我们将这个列输入两个一样的值试一试。
use person;
create table class (classes_id varchar(20) unique, count int);
insert into class values("一班",50);
insert into class value("二班",40);
insert into class value("一班",40);
我们可以看到,当在class_id 中加上了unique的约束条件之后,我们就不能在这一列输入两个一样的数字或者字符串了。
3、default:
作为一个设置默认值的主键,就可以把没有赋予的值自动转换成默认值。
4、primary key:
我们新创建一个class类,这次我们用primary key约束进行创建
use person;
create table class(class_id int primary key);
insert into class values(1),(2),(3),(4);
我们可以看到,我们创建了一个班级表,里面有1,2,3,4班,为了验证primary key是不是真的有not null 和 unique的作用之和,我们分别进行一次插入空值和插入重复值的操作
insert into class values(null);
insert into class values(1);
从结果我们可以明显的看到primary key 制止了null值和重复值的传入,我们由此可以验证primary key 约束有着not null 和 unique的共同性质。
5、foreign key 外键:
如果说以上的四个约束都是在一个表的内部进行的约束,我们的foreign key 就可以对另一个表和这一个表进行约束。foreign key 的意思就是将一张表的其中一个列于另外一张表的列进行关联,被foreign key 修饰的一个列创建新的值的必要条件是另外一个表中被primary key 修饰的列必须存在的值,解释的有些拗口,咱们直接看例子。
列如,有一张班级表,class 和一张学生表,我们要求学生输入的信息中带有学号,名字,数学成绩,语文成绩,英语成绩和所在的班级,其中,学生的班级的输入只能是class中所存在的。
我们单独的建立两张表很容易,我们现在要根据要求来建立class中的班级序号和student中所属班级的练习,做到只有student中输入的班级在class中存在才能存入数据库,如果不存在就不能被存入数据库。(做以下的例子之前先把之前的student和class表删除)
首先创建班级表:
use person;
create table class (class_id int primary key);
insert into class values(1),(2),(3),(4);
在创建学生表,其中的班级id要和class表中的class_进行链接。
create table student (id int, name varchar(20),
math double, english double, chinese double,
class_id int,
foreign key (class_id) references class(class_id));
我们输入新的测试数据。
insert into student values(1,'李四',78.56,89.56,45.67,1);
insert into student(id,name) values(2,'张三',1);
insert into student values(3,'王五',90.32,56.23,45.23,3),(4,'周六',89.45,98.56,95.23,4);
insert into student values(5,'周一',89.45,98.56,45.23,2);
insert into student values(6,'周二',78.56,89.56,45.12,2);
insert into student values(7,'孙权',78.23,65.09,56.23,1);
insert into student values(8,'孙策',89.23,85.12,82.12,3);
insert into student values(9,'孙坚',84.23,72.12,65.23,3);
insert into student values(7,'孙权策',78.23,65.09,56.23,4);
insert into student values(8,'孙策坚',89.23,85.12,82.12,4);
insert into student values(9,'孙坚权',84.23,72.12,65.23,2);
这些都能正确录入数据库,但是,当我们把班级写成除了1,2,3,4的任意一个数的时候:
就会发生错误。
(2)聚合查询
我们的一张表中往往有很多组数据,我们就用学生表为例,我们需要查询班级是一班的同学的平均成绩,这里就需要用到聚合查询。
1、聚合函数
函数 | 说明 |
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的 总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
conut:
我们在查询的时候可以在查询的列的后面加上count,来表示一共有多少列。
例如,根据我们之前创建的表,我们一共有多少学生在student表中:
select count(*) from student;
sum:
我们求一下数学成绩的平均值:
select sum(math) from student;
avg:
我们求一下总成绩的平均分:
select avg(math + chinese + english) as totla from student;
max:
我们求一下数学成绩最高的同学的分数:
select max(math) from student;
min:
我们求一下总成绩最低的同学的分数:
select min(chinese + math + english) as total from student;
2、group by函数
比如在一张student表中,我们有很多同学的信息,我们可以根据聚合查询的sum函数进行所有同学总成绩的查询,但是如果我们想将1,2,3,4班的同学分开,依次求出每个班同学的总分,我们应该怎么办呢?这时候我们可以考虑将同学们分成1,2,3,4组,每组代表对应的班级,然后再对每组的总成绩列进行sum即可。
select class_id,sum(chinese + math + english) from student group by class_id;
我们分析一下代码,因为student中class_id本来就只有1,2,3,4四个数值,我们按照四个数组,也就是四个班分成一组,对应的语句就是group by class_id。但是仅仅有分组还是不够的,我们还要根据需求求出本组的我们需要的值,可能是本组的最大值,平均值,最小值.....等等,所以,聚合函数是于group一起出现的,如果仅仅有group by 函数,没有聚合函数,那么分组就没有什么实质性的用处。
3、having语句
注意和where语句进行分开,where语句是再分组之前筛选值,而having语句是在分组之后筛选值。下面对比一下where语句和having语句
例如:查找每个班数学成绩在80~90的同学的总成绩。我们可以这样编写sql语句:首先查找80~90数学成绩的同学,通过where筛选出来,然后按照每个班进行分组,每组的值是这个班数学成绩80~90的同学的总成绩。
select class_id,sum(chinese + math + english) from student where math >= 80 and math <= 90 group by class_id;
上面的图是student表中的数据,下面的图是查询的结果,因为一班中没有任何同学的数学成绩达到标准,所以全部剔除,所以查询完的结果并没有一班。
以上是where,现在我们来看一下having:
例如,我们要查询总成绩大于500分的班级,我们需要先将班级分组,然后在求出总和,最后进行判断,也就是说在分完组之后进行判断,所以这里就应该使用having来进行比较。
select class_id,sum(chinese + math + english) as total from student group by class_id having sum(chinese + math + english) >= 500;
(3)多表查询(联合查询)
在实际的开发过程中,我们的数据往往不一定来自同一张表,而是多个表互相查询,共同作用的结果,在两张表中同时的查询数据就需要我们进行多表查询(也叫联合查询)。
联合查询就是对多张表取笛卡尔积,那可能有的同学就会问了,什么是笛卡尔积?
就是取表的全排列组合,举个例子。
表一:
a | b |
c | d |
表二:
e | f |
g | h |
笛卡尔积:我们把表一的第一行于表二的第一行,第二行连接起来,我们把表一的第二行与表二的第一行第二行连接起来,就形成了了表的全排列,也就是笛卡尔积后的表格。
a | b | e | f |
a | b | g | h |
c | d | e | f |
c | d | g | h |
在进行多表查询时,可以分为内连接,外连接和自连接。
1、内连接:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;
我们先创建一个老师表,teacher,其中包括了老师的姓名和所教的班级。
create table teacher (name varchar(20), class_id int, foreign key (class_id) references class(class_id));
insert into teacher values('李老师',1),('王老师',2),('吉老师',3),('刘老师',4);
我们想要查询学生表中的周一同学的老师是谁,因为student中没有老师的信息,所以我们就要进行多表查询。进行多表查询的时候,我们把student表和teacher表进行笛卡尔积,我们通过条件选择学生的姓名等于周一,并且使学生的班级id和老师的班级id相等,然后进行查询,我们就可以查询出我们要找的信息了。
select student.name, teacher.name from student, teacher where student.name ='周一' and student.class_id = teacher.class_id;
2、外连接
外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接,就是即使左边没有数据,我们采用右链接也会完全的显示出来左边。
左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;
我们插入一个没有成绩的同学
insert into student values(10,'Lora',null,null,null,4);
我们用外连接的方式查询所有4班的同学,采用右连接的方式。
我们本意是查询四班的同学,但是因为右链接,class的所有的值都会显示,因为又有条件(student.class_id = class.class_id )and (student.class_id = 4),所以左边的值全部显示空。
3、自连接:
自连接可以在同一张表的内部进行比较。