一、列属性
真正的对列的约束是依赖于数据的类型,但是这种约束比较单一,所以需要更多的约束,整个时候就是用到了字段的属性。
1.MySQL的记录长度
MySQL规定:一条记录最大只能有65535个字节。也就是64K。varchar的最大长度655356个字符。
而varchar还需要1-2个字节去记录长度。也就是说varchar永远存不满。
中文字符在不同编码下所占用的空间。
gbk:一个中文字符是2个字节,一个英文字符是一个字节。
utf8:一个中文字符是3个字节,一个英文字符是1个字节。
尝试使用最大空间建立数据库表:
create table mutf8(
name varchar(65535)
)charset utf8;
creaTE table mgbk(
name varchar(65535)
)charset gbk;
数据库忽略了varchar需要使用1-2个字节保存长度。
计算是能够使用的长度:
gbk:32767 * 2 +2 = 65536 所以 就变成 32766 2 + 2 = 65534
utf8:218453 +2 = 65537 21844*3+2 = 65534
建表语句变成:
create table mutf8(
name varchar(21844)
)charset utf8;
creaTE table mgbk(
name varchar(32766)
)charset gbk;
还有一个字节没有使用到。那是不是可以再加一个tinyint类型的字段进去?
alter table mgbk add num tinyint;
在MySQL中,如果一条记录着某一个字段位可以空的话,那么数据库就会使用一个字节去保存这种状态。
所以说要想完全的使用65535个字节的话,就要保证数据所有的字段都不能为null。
修改原来的name字段不为空:
alter table mgbk modify name varchar(32766) not null;
再去尝试添加新的tinyint字段:
alter table mgbk add num tinyint;
再去尝试添加新的tinyint字段:
alter table mgbk add num tinyint;
新增的字段也要保证不能为空
(null)
alter table mgbk add num tinyint not null;
2.null/not null 空属性
虽然MySQL字段默认的基本都是空类型,但是在实际开发过程中基本上要做到所有的数据字段不为空。
一旦出现某个字段可以为空的话,整个数据表查询就会变慢。
如何指定字段不为空:
定义的时候指定:
修改指定:
3.comment 列描述
描述:相当于注释,没有实际意义。专门用来描述字段的意义或者字段的数据格式。会随着表的创建语句一起保存,是用来给程序员或者DBA看的。
show create table table_name;
4.default 默认值
在实际中经常会发生某种数据在一开始就具有某个值。比如说人的年龄。一出生就是0.比如说表示数据是否宝删除的状态字段。0表示未删除,1表示已经删除。
软删除:基本上很少有数据是使用delete删除的。
创建数据表:我们去到了女儿国,要记录所有女儿国国民的表,要求有用户名,有用户的性别。
create table nrg(
usernam varchar(30) not null,
sex enum('男','女') default '女'
);
插入数据:
insert into nrg(usernam) values (‘月儿’);
注意: 有默认值得字段在数据插入的时候需要指定字段,默认值得字段直接忽略。
还有另外一种方式:使用default占位:
insert into nrg values(‘鱼儿’,default);
5.primary key 主键
主键是唯一标识数据库中的每一行(记录)的字段。所以主键是不能重复的,同时主键也不能为null。主键可以包含多个字段,但是一个表只能有一个主键。当主键包含多个字段的时候叫组合键或者复合主键。
为数据表增加主键的方法有三种:
第一种:在创建数据表的时候在字段的属性中申明添加。(只能指定一个字段)
--创建具有主键的数据表结构
学号,姓名,班级 ,学号作为主键
create table my_student (
name varchar(30) not null,
class char(4)
);
--添加学号字段
alter table my_student add num char(13) not null;
添加主键:
标准用法:
create table my_student (
num char(13) not null primary key,
name varchar(30) not null,
class char(4)
);
这种方式只能有一个字段是 主键。
第二种:在创建数据表的时候在建表语句的字段申明之后指定主键。(可以指定多个字段)
create table my_student(
num char(13) not null ,
name varchar(30) not null,
class char(4),
primary key(num,name) --可以指定多个表字段作为主键
);
第三种方式:当表已经创建好之后追加主键,可以修改表字段,也可以直接追加。
创建没有主键的表结构:
create table my_student(
num char(13) not null ,
name varchar(30) not null,
class char(4)
);
增加主键:
alter table my_student add primary key (num); --也可以指定多个表字段作为主键
这种方式要保证表中的主键字段的数据每一条都是唯一的。否则会产生错误。
插入数据:
insert into my_student values ('itzpark170101','李中渲',1701);
insert into my_student values ('itzpark170102','马建龙',1701);
insert into my_student values ('itzpark170103','弓嘉伟',1701);
insert into my_student values ('itzpark170101','史腾飞',1701);
更新主键:没有办法更新主键,只能删掉主键,再添加主键
删除主键:
alter table table_name drop primary key;
因为一个表只有一个主键,所以主键的删除非常的方便。
主键的分类:
在实际工作中,我们在创建表的时候一般很少用真实业务数据字段当做主键。如果使用了,那么我们把这种主键称为业务主键。比如学生的姓名。课程号之类的。大部分的时候是使用一个逻辑字段(字段没有实际的意义,同时字段的值对于整个数据行来说也没有什么影响)。将这种主键称之为逻辑主键。
例如:
create table student(
id int primary kry auto_increment comment ‘自增的 逻辑主键’,
num char(10) not null comment ‘学号’,
name varchar(30) not null comment ‘姓名’
)charset utf8;
6.auto_increment 自动增长
当对应的字段不给值或者给null的时候,系统会自动的从上一条数据中取值加一作为这个字记录的值。
任何一个字段想要设置自增长,必须是整数形式,同时必须是索引(也就是key栏位必须有值)。
测试:
alter table table_name modify num char(13) not null auto_incremrnt;
添加一个整数形式的字段:
alter table my_student add id int;
自增字段一般与主键一起使用:(因为自增字段必须是索引)
单独删除主键,自增属性不能存在。
添加主键:
alter table my_student add primary key (id);
再来也添加主键:
看图说话:主键只能唯一,主键的值不能重复,有重复值得字段不能设置为主键。
一张数据表只能有一个自增字段。
create table my_student(
num char(13) not null ,
name varchar(30) not null,
class char(4),
id int not null ,
ip int not null,
primary key(id,ip)
);
插入数据:
insert into my_student(num,name,class,ip) values( 'itzpark170101','李中渲',1701,1);
默认的自增长是从1开始的。但是可以使用指定值改变自增的原本数值。
查看下一个自增字段增长的数值是多少:
show create table table_name;
修改自增字段:
如果要修改的是自增长的字段,那么只能先删除再添加(因为一个表只能有一个自增的字段)。
修改当前自增长的值:修改的值只能比当前自增长的最大值大。小不生效。
alter table table_name auto_increment=数值
思考问题:为什么自增长的字段是从1开始的?为什么自增长的值每次都是1?
系统的所有实现都是由系统的变量来控制的。
查看系统变量的命令:
show variables like ‘%auto_increment%’;
修改自增变量的值:
set 变量名 = 变量值
删除自增长:
alter table table_name modify 字段 字段属性 去掉主键;
7.unique key 唯一键
一张表当中往往有一些字段他的值是不能重复的。但是一张表中只能有一个主键。唯一键就是解决表中多个字段需要唯一约束的问题。
唯一键的本质与主键差不多。唯一键允许默认为空,并且允许多个字段为空。为空字段不参与唯一性比较。
添加唯一键的方法:
方法一:在创建表的时候,在字段之后添加unique 或者 unique key.
create table munique(
num char(10) not null unique comment '编号',
name varchar(30) not null comment '姓名'
);
这种语发只能将唯一键建立在一个字段上,无法使用多字段唯一键。
PRI 属性可以表示本字段是主键也能表示本字段是唯一键。
方法二:在所有的字段之后增加unique key 申明。
create table munique1(
num char(10) not null comment '编号',
name varchar(30) not null comment '姓名',
unique key(num)
);
显示为PRI是因为这个表没有主键。而刚好有唯一键。唯一键的本质与主键是相同的。
这种语法可以指定多个字段作位唯一键。
方法三:在创建完表之后,追加unique键。
create table munique3(
id int not null primary key auto_increment,
num char(10) not null comment '编号',
name varchar(30) not null comment '姓名'
);
-追加unique key
完全使用的是修改表字段的语法:
alter table table_name modify num char(10) not null unique key ;
使用添加表字段的语法。
alter table table_name add 字段 字段属性 unique;
唯一键的修改与删除:
修改:唯一键可以使用先删除后新增的方式进行修改。但是也可以不删除,因为唯一键可以有多个。
删除:
alter table drop primary key; --删除主键的操作。(因为主键是唯一的)
alter table drop unique key ; --错误,唯一键可以有多个(因为唯一键是可以有多个)
alter table drop index 索引名称; --唯一键本质是一个索引
使用 desc只能看到表结构,不能看到索引的有关信息。
如何去查看索引的有关信息,索引也是同表的检表语句一起保存的。
二、索引
几乎所有的索引都是建立在表字段之上的。
索引:系统根据某种算法,将表中的数据能够快速的进行匹配。能够快速的找到需要的记录一种机制。
索引的作用:
提高数据的查询效率。
对数据的格式进行约束(比如唯一性)。
增加索引的影响:
增加索引后会产生索引文件,并且有的时候可能比数据本身还要大。所以建立索引是会产生空间消耗的。同时由于约束条件,数据插入的时候会比较慢。
什么时候要建立索引:
如果某个字段需要作为查询的条件经常使用。比如根据学号去查询学生的信息。
如果某个字段需要进行明确的数据约束。比如唯一性索引。
MySQL中的索引:
主键索引
唯一索引
普通索引
全文索引
其中最最难的是全文索引。
全文索引最大的苦难是关键字的确定。
英文的全文索引比较简单:因为单词与单词之间是有空格的。
中文很难:中文之间没有空格,而且分词也比较困难。sphinx分词
三、数据的高级操作
数据的操作:增删改查(CURD)
8.新增数据
基本语法:
insert into table_name(字段1,字段2,。。。) values (值1 ,值2,。、。);
insert into table_name(字段1,字段2,。。。) values(值1 ,值2,。、。),
(值1 ,值2,。、。),(值1 ,值2,。、。),(值1 ,值2,。、。);
我们操作主键的时候,有这样一种情况,当数据表中以及存在数据的时候,再次插入数据,如果主键发生冲突,那么会产生错误。
遇到这种情况,我们可以先将已经存在的数据删除掉,然后添加新的数,也可以修改新数据的主键值。
但是我们一般期望能够有更好的办法解决这种问题。
1)主键冲突
第一种:当主键冲突的时候修改:
insert into table_name [字段列表] values(值列表) on duplicate key update 内容;
当我出现主键冲突的时候指定更新内容比较麻烦,有没有什么办法将所有不同的内容全部更新。
第二种办法:替换
replace into table_name(字段列表) values (值列表);
注意:值列表和字段列表都要包含主键字段。
2)蠕虫复制
根据已经存在的表快速创建新表:
create table new_table_name like old_table_name;
表结构完全一致:
看图说话:
表的组成有两部分构成,表的结构和表的数据。
通过like创建的表只会复制表的结构,不会复制表数据。
蠕虫复制:
有了表结构,如何能够将表的数据也复制过来,这种办法叫蠕虫复制。
insert into new_table_name select */字段列表 from old——table_name;
蠕虫复制的作用:
1.能够从一张表的数据复制到另一张表。
2.能够快速的使得一张表的数据增加到一定的范围,一般用于检测数据的数据抗压能力和性能。
9.修改数据
基本语法:
update table_
name set 字段=值,字段=值。。 where 条件;
要注意修改时候的where条件,因为没有条件的修改会修改整个数据表。
限制级修改:
update table_name set 字段=值,字段=值。[where 条件] limit 数字;
意思:修改指定数据的值,要按照指定的数量去修改。
但是如果数据库的数据比较多,多到了一定的数量级,任何长时间的操作都有可能造成系统宕机。
所以要尽可能的控制一次性修改的数据量。所以会在修改操作的最后添加一个limit的限制条件。
说明这种语法每次都是从第一行数据开始,进行匹配,找到符合数量的数据进行修改。如果不需要修改也不会再去匹配其他的数据。
1.删除数据
基本语法:
delete from table_name where 条件;
高级用法:限制删除数量
delete from table_name where 条件 limit 数量;
11.查询数据
查询操作的常规语法:
select */字段 from table_name [where 条件];
完整的查询语法:
select[select选项] */字段列表[字段别名] from 数据源 [where 条件子句][group by 子句][having子句] [order by 子句][limit 子句];
1)select选项
select 选项会对查出来的数据进行处理
select 选项有两种:
all :全部的数据,默认的select是all 。
distinct:去除重复,重复是针对所有查询的数据列。
2)字段别名
当数据查询出来的时候字段的名称不能够满足实际的需求,特别是在多表查询的时候,如果表中具有相同的字段。就去要给字段起个别名。
基本语法:
字段名 as 别名
例如 :
name as 姓名
sex as 性别
3)数据源
数据源:数据的来源。关系型数据库的数据源都是数据表。
数据源分为:单表数据源,多表数据源,查询结果。
单表数据源:
select from table_name;
多表数据源:
select 字段/* from table1,table2 where 条件;
查询结果来源:数据的来源是一条查询语句。
select * from (select 语句) as 表名;
4)where子句
where子句是一个判断条件,比如where id>8;
where子句返回的是 TRUE 或者FALSE,也就是0或者1.
判断条件:>,<,=,>=,<= , like , between and , in /not in, && ,|| ,! and or
like:模糊匹配,左右两边都可以使用% ,%是一个占位符,表示可以是任何符号。
in 与not in 相当于数组
where原理:where是唯一一个从磁盘获取数据的时候进行判断的条件,从磁盘取出一条记录,如果符合条件放入内存,否则直接放弃。保证取出来的就是有效数据。
练习:
查询学生ID为 1或者3或者5的学生信息
select * from student where id in (1,3,5);
select * from student where id=1 || id=3 || id=5;
查询学生年龄在20-25之间的学生信息:
select * from student where age between 20 and 25;
select * from student where age>=20 && age <=25;
5)group by 子句
group by 字段 : 按照什么字段分组。
在使用group by 查询的时候,每一个分组只是出来了一条数据。事实上group by是进行分组统计的,而不是进行分组查询的。
group by分组基本上都是和数据统计一起使用的。没有统计函数的group by 没有实际意义。
SQL提供了一组的数据统计函数(聚合函数)。
count():计算结果的条数。
max():计算指定字段的最大值。
min():计算制定字段的最小值。
avg():计算制定字段的平均值。
sum():计算指定字段的和。
count:count()的参数可以使* ,表示所有的字段。也可以指定字段。但是字段的值为null的时候统计不计数。
分组排序:ASC/DESC:是对分组的整个结果进行排序,而不是对分组的内部进行排序。
ASC :升序排序。默认的排序方式。
DESC:降序排序。
多字段分组:
先对一个字段进行分组,分组之后在分组中再按照另外一个字段分组。
查询每个班级男生与女生的数量
select cid,sex,count(sex) from student group by cid,sex;
需求:有的时候我们进行分组之后还需要获取储所有分组数据的某个字段。
比如说:要获取储所有分组之后的人名。
group_concat(字段) --获取分组中所有数据的某个字段
select cid,sex,count(sex),group_concat(name) from student group by cid,sex;
将上面的显示结果按照先class升序排列,然后在按照班级降序排列
回溯统计:with rollup;
任何一个分组之后都会有一个小组,在这个小组上再次进行统计就可以使用with rollup。
注意:with rollup 与order by是互斥的操作。
单字段分组排序,最后统计的是这个分组的总和。多字段分组之后,with rollup 最后统计的是各个分组内部的总和各进行一次统计,最后再来一次所有分组的统计。
6)having子句
having子句与where子句一样,是进行数据条件筛选的。
where与having的区别
where子句是磁盘级别的。只有符合where子句判断的才会进入内存,group by是将进入内存的数据进行分组。如果需要对分组之后的数据进行过滤选择,那么就要使用having子句。
having可以实现where的所有操作,但是where不一定能够实现having的所有操作。
查询出所有班级ID大于2的学生,并且按照班级进行分组。
select * from student where classid>2 group by cid;
select * from student group by cid having cid>2;
查询所有学生人数大于2的班级
select cout(*) from student group by cid;
select cout(*) from student where cout(*)>2 group by cid;
hanving是内存级查询,能够使用分组,统计以及 别名等进入内存之后才会产的查询条件。
总结
注意:
1. 分组查询只能在having里面使用,不能够在where里面使用。因为where的时候还没有分组统计的结果。
2.having能够使用字段的别名,但是where不行,原理类似。别名也是在进入内存之后添加的。
3.能够使用where尽量使用where,因为where能够讲数据提前在进入内存的时候过滤掉。提高内存的利用率。
7)order by 子句
order by:排序,根据某个字段进行升序或者降序排序,需要依赖校对集。
基本语法: order by 字段[ASC |DESC]
排序可以进行多字段排序:
多字段排序的时候,先根据某个字段进行排序,然后在排好序的内部再根据第二个字段进行排序。所以,第二个字段不会影响第一个字段的排序。
8)limit 子句
limit子句是一种限制结果的子句。在一定程度上可以实现数据获取量的安全性。
limit有两种使用方式。
第一种:只用来限制记录的数量:
limit 数量;
第二种使用方式:
limit 起始位置,数量;
这种方式主要用于实现分页功能。
可以根据用户操作的页码数改变limit的起始位置。后面的数据量是不会改变的,也就是每页的分页数量数(展示条数)不会变化的。
起始位置 = (页数-1)* 数量
数据库的内容在计数的时候是从0开始的。
select * from my_student1 limit 5,5;
四、联合查询
1.使用场景
当数据表的数据量比较大的时候,我们有时会进行分表切割,将数据按照一定的规则存放在不同的数据表中,但是每个表的数据结构是完全相同的,比如我们按照省份进行会员的存储。
查询同一张表,但是对于数据的排序操作是不同的,比如男生身高升序,女生身高降序。
那么在我们需要查询每个省份前10位用户的时候就可以使用联合查询。
2.基本语法:
select 语句1
union [union选项]
select 语句2;
注意:两个数据表的查询可以在不同的数据表中,但是查询结果的字段以及字段的顺序必须一致。
union选项:
union选项与select选项一样,都是两个。
all :保留所有。
distinct :去除重复(默认的)。
3.联合查询结果集排序
看图说话:
如果第二个查询语句中具有排序,那么最终会全部按照这个排序进行。
select 排序控制:
可以使用()将两个语句完全分割开查询。
也可以使用()对单个select进行排序。
可以在单个select语句最后添加limit,limit行数尽量设置的大些。
五、连接查询
数据库的数据表一般只存储一个方面的内容,所以在有些时候如果想要获取完整的数据就需要使用几张表之间的关联条件连接多张表进行查询。
需求:查询一下某个学生的所有班级信息。
学生信息保存在学生表中,班级信息报讯在班级表中,如何根据学生的信息查询到班级表中的信息。
连接查询的分类:SQL中将连接查询分为四类:内连接,外连接,自然连接和交叉连接。
语法: 左表 join 右表
左表:在join左边的表
右表:在join右边的表
1.交叉连接
cross join : 交叉连接。
从一张表中循环取出每一条记录,然后与另外一张表中的的每一条数据进行匹配(无条件匹配),每一条数据都会保留。而连接之后的字段也都会保留。这种方式也叫笛卡尔积。
基本语法:左表 cross join 右表 ;=== from 左表,右表
学生表与教师表交叉连接:
查看两张表的数据。
select * from table_name;
两张表进行交叉连接,理论上会产生4*3 = 12条数据。
select * from student cross join teacher;
select * from 是查询语句
student cross join teacher 整体是数据源。
也就是说交叉查询的数据一定是在经过全部交叉运算之后才会进行取数据的。
笛卡尔积本身没有意义,所以交叉连接没有意义。应该竟可能的避免进行交叉连接。
2.内连接
内连接 :[ inner] join;
从左表中取出每一条记录,去与右表中的每一条记录进行匹配,匹配的结果必须是某个条件在左表中与在右表中相同再回最终保留这条匹配结果。
基本语法:左表 【inner 】 join 右边 on 左表.字段 = 右表.字段
on表示连接条件。左表的字段与右表的字段表示相同的业务意义。
select * from student inner join class on student.cid = class.id ;
当字段在两个表中中是唯一的时候可以省略表名称
select * from student inner join class on cid = class.id ;
下面的这表SQL是错误的,因为ID在两个表中都有
select * from student inner join class on student.cid = id ;
在进行多表连接查询的时候,如果不同的表右相同名称的字段,需要给字段前加上表的名称作为前缀,或者使用as起别名。
select s.*,c.name as c_name ,c.root -- 字段别名
from student as s inner join class as c -- 表别名
on s.cid = c.id;
内连接可以没有连接条件,在没有连接条件的情况下。内连接相当于交叉连接(笛卡尔积)。
内连接的on条件可以使用where条件替换。但是通常不会使用where替代on,因为on的效率更高。
3.外链接
外链接:以某张表为准,取出表中的所有字段然后与另一张表中的每一条记录进行匹配,不管能不能匹配上连接条件,最终都会保存。如果能够匹配上匹配条件,正确保存,如果不能匹配,那另一张表的字段全部为null值。
外链接有两种:以某个表作为准,那个表作为主表进行关联。主表的字段都是有值得。
左外连接(左连接):left join 以左表为主表
右外连接(右连接):right join 以右表为主表
基本语法:
左表 left/right join 右表 on 左表.字段 = 右表.字段;
左外连接
select s.*,c.name as c_name ,c.root
from student as s left join class as c
on s.cid = c.id;
右连接
select s.*,c.name as c_name ,c.root
from student as s right join class as c
on s.cid = c.id;
左连接与右连接的数据量都是等于主表的数据条数。
左连接与右连接的主表是不一样的,但是显示的时候总是左表的字段在左,右表的字段在右。左右连接可以相互之间互相转换。只是数据表的顺序不一样。
4.自然连接
自然连接:natural join :自动连接,自动匹配连接条件。
系统以字段的名称作为匹配的条件(同名的字段作为连接条件,多个同名字段都会作为条件)
自然连接也分为:自然内连接 和 自然外链接
自然内连接:
自然外链接: