[TOC]python
数据库
""" 一、什么是数据库:管理数据的系统 - 安装某种管理数据的系统 - 管理的对象本质是文件 二、存储数据的位置:内存、硬盘 三、什么是系统:运行在硬件基础上,管理其余软件 """ # 数据库的组成 """ 库:存放多张表 - 文件夹 表:包含多条相同结构的记录 - 文件 记录:包含多个key-value键值对的一条数据 - 二进制数据 字段:描述信息 - 信息自己 == key-value - 二进制数据 stu id name age gender 1 Bob 18 男 2 Tom 17 女 ... teacher ... """
数据库的分类
# 1)关系与非关系 # 关系:数据库中表与表之间有联系 - mysql # 非关系:没有表概念 - redis、mongodb(介于关系与非关系) # 2)内存与硬盘 # 硬盘:数据能够永久存储 - mysql、mongodb # 内存:数据的存取效率极高 - redis、memcache # 3)sql与nosql # sql:数据库操做经过sql语句 # nosql:数据库操做就是key-value形式(value就是一条记录) # stu - {'name': 'Bob', 'age': 18} # stus - [{'name': 'Bob', 'age': 18}, {'name': 'Tom', 'age': 18}] # name - 'Jerry'
安装
""" 一、解压免安装版本(5.6 - 没有初始密码) 二、配置环境变量:数据库绝对路径下的bin 三、配置服务: 启动管理员终端:mysqld --install [nmysql] #安装服务端 """
卸载
""" 前提)启动终端,输入 mysql,若是不是提示 不是内部或外部命令,表明已安装数据库 1)直接连入 i 搜索:服务,检索mysql服务,有 中止服务,并移除服务 - 启动管理员终端:mysqld --remove ii 搜索:服务,检索mysql服务,无 (mysql使用命令启动) 中止服务,启动管理员终端 tasklist | findstr mysql taskkill /pid 进程pid /f 2)链接超时 搜索:服务,检索mysql服务,移除服务便可 3)移除环境变量 总结:若是能连入,先中止服务 | 若是添加了服务,就移除服务 | 取消环境变量配置 """
链接数据库
1)游客登录(不必定能登入,登入了也啥都不能干) >: mysql 2)帐号密码登陆 >: mysql -u root -p[密码] 再输入密码,没有任何提示,没有密码直接回车 3)链接指定服务器的mysql >: mysql -h ip地址 -P 端口号 -u 帐号 -p[密码] 回车后敲入密码 eg: >: mysql -hlocalhost -P3306 -uroot -p[密码] 4)退出数据库 >: quit >: exit
用户信息查看
1)查看当前登陆的用户 mysql>: select user(); mysql>: select version(); 查看mysql版本: 2)root权限下能够查看全部用户信息 mysql>: select * from mysql.user; #查看全部用户的全部信息 mysql>: select * from mysql.user \G; #查看全部用户的权限 mysql>: select user,password,host from mysql.user; #查看全部用户的(user,password,host) 3)root登陆下,删除游客(操做后要重启mysql服务) mysql>: delete from mysql.user where user=''; 4)root登陆下,修改密码(操做后要重启mysql服务) mysql>: update mysql.user set password=password('12345678') where host='localhost'; updata mysql.user set password=password('root') where host='localhost'; 5)没有登陆 >: mysqladmin -u用户名 -p旧密码 -h域名 password "新密码" eg>: mysqladmin -uroot -p12345678 -hlocalhost password "root" 6)root登陆下,建立用户 mysql>:grant 权限们 on 数据库名.表名 to 用户名@主机名 identified by '密码';
数据库的基本操做
1)查看已有数据库(当前用户能够操做的)全部数据库 mysql>:show databases; 2)选择某个数据库 mysql>:use 数据库名 #进入某个具体的数据库,能够直接对该数据库下的表进行操做,不须要用 . 3)查看当前所在数据库 mysql>:select database(); #须要经过 use 进入具体数据库,并查看当前数据库锁拥有的表 4)建立数据库 mysql>:create database 数据库名 [charset=编码格式]; #不指定编码格式的话,默认为latin1 eg>: create database owen; eg>: create database zero charset=utf8; eg>: create database tank; 5)查看建立数据库的详细内容 mysql>:show create database 数据库名; eg>: show create database owen; 6)删除数据库 mysql>: drop database 数据库名; eg>: drop database tank; 7)修改字符编码 mysql>: alter database 数据库名 charset=编码格式;
SQL语句、语句扩展
top:TOP 子句用于规定要返回的记录的数目。 列(s) = * sql top 语法 select top number|precent 列(s) from table_name; # 列(s) 表示 全部的列名称 top number例:select top 2 * from table_name; 或 select * from table_name limit 2; top precent例:select top 50 precent * from table_name; # 选取表中50%的记录 like:LIKE 操做符用于在 WHERE 子句中搜索列中的指定模式 sql like 语法 select 列(s) from table_name where 列 like pattern; 例:select * from table_name where 列 like 'A%'(在表中搜寻以A开头的)|'%B'(以B结尾的)|'%AB%'(包含AB的); in:IN 操做符容许咱们在 WHERE 子句中规定多个值 sql in 语法 select * from table_name where 列 in(值1,值2,...); between:操做符 BETWEEN ... AND 会选取介于两个值之间的数据范围。这些值能够是数值、文本或者日期。 sql between 语法 select * from table_name where 列 between 值1 and 值2; # 范围取头不取尾 alias:为列名称和表名称指定别名(Alias)。 sql alias 语法 表:select * from table_name as alias_name; 表别名例:select p.列1,p.列2,p.列3 from table_name1 as p,table_name2 as po where p.列1='值1' and p.列2='值2'; 列:select 列 as alias_name from table_name; 列别名例:select 列1 as alias_name1,列2 as alias_name2 from table_name; join:用于根据两个或多个表中的列之间的关系,从这些表中查询数据。 sql join 语法 select tb1.列1,tb1.列2,tb2.列 from tb1 inner join tb2 on tb1.列3=tb2.列3 order by tb1.列1; 或 select tb1.列1,tb1.列2,tb2.列 from tb1,tb2 where tb1.列3=tb2.列3; 备注:不一样的 SQL JOIN 除了在上面的例子中使用的 INNER JOIN(内链接),还能够使用其余几种链接。 下面列出了能够使用的 JOIN 类型,以及它们之间的差别。 JOIN: 若是表中有至少一个匹配,则返回行 LEFT JOIN: 即便右表中没有匹配,也从左表返回全部的行 RIGHT JOIN: 即便左表中没有匹配,也从右表返回全部的行 FULL JOIN: 只要其中一个表中存在匹配,就返回行 inner join 关键字语法:在表中存在至少一个匹配时,INNER JOIN 关键字返回行。 select * from tb1 inner join tb2 on tb1.列=tb2.列; # inner join 与join是相同的 left join 关键字语法:LEFT JOIN 关键字会从左表(tb1)那里返回全部的行,即便在右表(tb2)中没有匹配的行。 select * from tb1 left join tb2 on tb1.列=tb2.列; right join 关键字语法:RIGHT JOIN 关键字会右表(tb2)那里返回全部的行,即便在左表(tb1)中没有匹配的行。 select * from tb1 right join tb2 on tb1.列=tb2.列; full join 关键字语法:只要其中某个表存在匹配,FULL JOIN 关键字就会返回行 select * from tb1 full join tb2 on tb1.列=tb2.列; 十一、union:用于合并两个或多个 SELECT 语句的结果集(UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有类似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同) sql union 与 union all 语法 select * from table_name1 union select * from table_name2; select * from table_name1 union all select * from table_name2; 备注:默认地,union 选取不一样的值,若是容许重复的值,就使用 union all(列出全部的值) select into:从一个表中选取数据,而后把数据插入另外一个表中。经常使用于建立表的备份复件或者用于对记录进行存档。 sql select into 语法 select * into new_table_name [in externaldatabase] from old_table_name; # 全部列插入新表 select 列 into new_table_name [in externaldatabase] from old_table_name; # 某一列插入新表 例:备份某张表 select * into tb1_backup from tb1; 向另外一个数据库中拷贝表 select * into tb1 in 'backup.mdb' from tb1; 多表查询存入到新表 select tb1.列1,tb2.列2 into new_table_name from tb1 inner join tb2 on tb1.列3=tb2.列3; create index:用于在表中建立索引。在不读取整个表的状况下,索引使数据库应用程序能够更快地查找数据。 注释:更新一个包含索引的表须要比更新一个没有索引的表更多的时间,这是因为索引自己也须要更新。所以,理想的作法是仅仅在经常被搜索的列(以及表)上面建立索引。 sql create index 语法 create index index_name on table_name(列); # 简单的索引,容许使用重复的值 create index index_name on table_name(列1 desc,列2); # 默认是升序,但愿降序在列名称后添加保留字 desc,索引不止一个列能够逗号隔开 sql create unique index 语法 # 惟一的索引 create unique index index_name on table_name(列); # 惟一的索引意味着两个行不能拥有相同的索引值 alter table : 语句用于在已有的表中添加、修改或删除列。 sql alter table 语法 添加列:alter table table_name add 列 数据类型; 删除列:alter table table_name drop column 列; 改变列中数据类型:alter table table_name modify column 列 须要修改的类型; 只修改列的数据类型的方法: 一般能够写成 alter table 表名 modify column 列名 新的列的类型 例如:student表中列sname的类型是char(20),如今要修改成varchar(20),SQL语句以下 alter table student modify column sname varchar(20); 同时修改列名和列的数据类型的方法: 一般能够写成 alter table 表名 change column 旧列名 新列名 新的列类型 例如:student表中列sname的类型是char(20),如今要修改成stuname varchar(20),SQL语句以下 alter table student change column sname stuname varchar(20); alter table table_name add <新列名> <数据类型> [约束条件][FLRST(添加列到表的最前面)|AFTER(指定列后面) <已存在的列>]; # 添加列 alter table table_name <旧列名> <新列名> <新数据类型>; # 修改列名 alter table table_name modify <列名> <数据类型>; # 修改列的数据类型 alter table table_name modify <列1(想要改变的列)> <数据类型> FLRST|AFTER <列2>; # 修改列的位置 alter table table_name drop <列>; # 删除列 alter table <旧表名> rename to <新表名>; # 修改表名 view(视图): 视图是可视化的表。视图包含行和列,就像一个真实的表 注释:数据库的设计和结构不会受到视图中的函数、where 或 join 语句的影响。 sql create view 语法 create view view_name as select 列(s) from table_name where 条件; 注释:视图老是显示最近的数据。每当用户查询视图时,数据库引擎经过使用 SQL 语句来重建数据。 更新视图:create or replace view view_name as select 列(*) from table_name where 条件; 删除视图:drop view view_name;
数据库配置
# 经过配置文件统一配置的目的:统一管理 服务端(mysqld) 、客户端(client) # 配置了 mysqld(服务端) 的编码为utf8,那么再建立的数据库,默认编码都采用utf8 # 配置流程 # 1)在mysql安装根目录下,建立配置文件:my.ini # mac下配置文件名叫 my.cnf # 2)设置配置文件内容并保存 [mysqld] # 服务器配置 port=3306 # 能够修改数据库默认端口(若是数据库端口被其余软件占用) character-set-server=utf8 # 编码格式 #非安全模式 sql_mode = no_engine_substitution #安全模式 #sql_mode = strict_trans_tables #设置引擎 default-storage-engine=INNODB collation-server=utf8_general_ci # 排序方式(默认跟编码格式走) #utf8_general_ci 不区分大小写,这个你在注册用户名和邮箱的时候就要使用。 #utf8_general_cs 区分大小写,若是用户名和邮箱用这个 就会照成不良后果 #utf8_bin:字符串每一个字符串用二进制数据编译存储。 区分大小写,并且能够存二进制的内容 [client] # mysql本身的客户端叫[mysql],配置[client]即配置了[mysql],也配置了其余存在方式的客户端,好比Navicat可视化客户端 default-character-set=utf8 # 编码格式 # 3)重启数据库服务
用户操做:重点
# 为特定的数据库分配有该数据库 操做权限 的用户 mysql>: grant 权限们 on 数据库.表 to 用户名@'主机名' identified by '密码'; # 1)all:全部权限 # 2)oldboy.*:oldboy数据库下全部表 # 3)oldboy@'localhost':本机能够经过oldboy用户登入 # 4)identified by 'Oldboy123':密码为Oldboy123 eg>: grant all on oldboy.* to oldboy@'localhost' identified by 'Oldboy123'; # 1)select,delete,update,insert,drop,alter:指定的权限 # 2)oldboy.*:oldboy数据库下全部表 # 3)oldboy@'%':任何机器能够经过oldboy用户登入 # 4)identified by 'Oldboy123':密码为Oldboy123 eg>: grant select,delete,update,insert,drop,alter on oldboy.* to oldboy@'%' identified by 'Oldboy123'; # 撤销权限 mysql>: revoke 权限1,权限2,... on 数据库名.表名 from 用户名@'主机名'; # 禁掉本地oldboy用户对oldboy数据库的全部表的drop权限 eg:> revoke drop on oldboy.* from oldboy@'localhost'; # 删除用户 drop user 用户名@'主机名';
数据库表的引擎:驱动数据的方式 - 数据库优化
# 前提: 引擎是建表是规定, 提供给表使用的, 不是数据库 # 展现全部引擎 mysql> show engines; # innodb(默认): 支持事务, 行级锁, 外键 mysql>: create table t11(id int)engine=innodb; # myisam: 查询效率要优于innodb, 当不须要支持事务, 行级锁, 外键, 能够经过设置myisam来优化数据库 mysql>: create table t12(id int)engine=myisam; # blackhole:黑洞,存进去的数据都会消失(能够理解不存数据) mysql>: create table t13(id int)engine=blackhole; # memory:表结构是存储在硬盘上的,可是表数据所有存储在内存中 mysql>: create table t14(id int)engine=memory;
MySQL各大存储引擎:
最好先看下你下的MySQL支持什么数据库引擎mysql
存储引擎主要有: 1. MyIsam , 2. InnoDB, 3. Memory, 4. Blackhole, 5. CSV, 6. Performance_Schema, 7. Archive, 8. Federated , 9 Mrg_Myisamlinux
可是咱们主要分析使用MyIsam 和InnoDB。其他略微带过,详情请分别百度。程序员
(1)InnoDB:
定义:(默认的存储引擎)web
InnoDB是一个事务型的存储引擎,有行级锁定和外键约束。redis
Innodb引擎提供了对数据库ACID事务的支持,而且实现了SQL标准的四种隔离级别,关于数据库事务与其隔离级别的内容请见数据库事务与其隔离级别这类型的文章。该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它自己其实就是基于MySQL后台的完整数据库系统,MySQL运行时Innodb会在内存中创建缓冲池,用于缓冲数据和索引。可是该引擎不支持FULLTEXT类型的索引,并且它没有保存表的行数,当SELECT COUNT(*) FROM TABLE时须要扫描全表。当须要使用数据库事务时,该引擎固然是首选。因为锁的粒度更小,写操做不会锁定全表,因此在并发较高时,使用Innodb引擎会提高效率。可是使用行级锁也不是绝对的,若是在执行一个SQL语句时MySQL不能肯定要扫描的范围,InnoDB表一样会锁全表。算法
//这个就是select锁表的一种,不明确主键。增删改查均可能会致使锁全表,在之后咱们会详细列出。 SELECT * FROM products WHERE name='Mouse' FOR UPDATE;
适用场景:sql
1)常常更新的表,适合处理多重并发的更新请求。mongodb
2)支持事务。数据库
3)能够从灾难中恢复(经过bin-log日志等)。
4)外键约束。只有他支持外键。
5)支持自动增长列属性auto_increment。
MySQL官方对InnoDB的讲解:
1)InnoDB给MySQL提供了具备提交、回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。
2)InnoDB锁定在行级而且也在SELECT语句提供一个Oracle风格一致的非锁定读,这些特点增长了多用户部署和性能。没有在InnoDB中扩大锁定的须要,由于在InnoDB中行级锁定适合很是小的空间。
3)InnoDB也支持FOREIGN KEY强制。在SQL查询中,你能够自由地将InnoDB类型的表与其它MySQL的表的类型混合起来,甚至在同一个查询中也能够混合。
4)InnoDB是为处理巨大数据量时的最大性能设计,它的CPU效率多是任何其它基于磁盘的关系数据库引擎所不能匹敌的。
5) InnoDB被用来在众多须要高性能的大型数据库站点上产生。
**补充:**什么叫事务?简称ACID
A 事务的原子性(Atomicity):指一个事务要么所有执行,要么不执行.也就是说一个事务不可能只执行了一半就中止了.好比你从取款机取钱,这个事务能够分红两个步骤:1划卡,2出钱.不可能划了卡,而钱却没出来.这两步必须同时完成.要么就不完成.
C 事务的一致性(Consistency):指事务的运行并不改变数据库中数据的一致性.例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变.
I 独立性(Isolation):事务的独立性也有称做隔离性,是指两个以上的事务不会出现交错执行的状态.由于这样可能会致使数据不一致.
D 持久性(Durability):事务的持久性是指事务执行成功之后,该事务所对数据库所做的更改即是持久的保存在数据库之中,不会平白无故的回滚.
(2)M4yIsam:
定义:
MyIASM是MySQL默认的引擎,可是它没有提供对数据库事务的支持,也不支持行级锁和外键,所以当INSERT(插入)或UPDATE(更新)数据时即写操做须要锁定整个表,效率便会低一些。
MyIsam 存储引擎独立于操做系统,也就是能够在windows上使用,也能够比较简单的将数据转移到linux操做系统上去。
意味着:引擎在建立表的时候,会建立三个文件,一个是.frm文件用于存储表的定义,一个是.MYD文件用于存储表的数据,另外一个是.MYI文件,存储的是索引。操做系统对大文件的操做是比较慢的,这样将表分为三个文件,那么.MYD这个文件单独来存放数据天然能够优化数据库的查询等操做。有索引管理和字段管理。MyISAM还使用一种表格锁定的机制,来优化多个并发的读写操做,其代价是你须要常常运行OPTIMIZE TABLE命令,来恢复被更新机制所浪费的空间。
适用场景:
1)不支持事务的设计,可是并不表明着有事务操做的项目不能用MyIsam存储引擎,能够在service层进行根据本身的业务需求进行相应的控制。
2)不支持外键的表设计。
3)查询速度很快,若是数据库insert和update的操做比较多的话比较适用。
4)成天 对表进行加锁的场景。
5)MyISAM极度强调快速读取操做。
6)MyIASM中存储了表的行数,因而SELECT COUNT(*) FROM TABLE时只须要直接读取已经保存好的值而不须要进行全表扫描。若是表的读操做远远多于写操做且不须要数据库事务的支持,那么MyIASM也是很好的选择。
缺点:
就是不能在表损坏后恢复数据。(是不能主动恢复)
补充:ISAM索引方法–索引顺序存取方法
定义:
是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到 数据库被查询的次数要远大于更新的次数。
特性:
ISAM执行读取操做的速度很快,并且不占用大量的内存和存储资源。
在设计之初就预想数据组织成有固定长度的记录,按顺序存储的。—ISAM是一种静态索引结构。
缺点:
1.它不 支持事务处理
2.也不可以容错。若是你的硬盘崩溃了,那么数据文件就没法恢复了。若是你正在把ISAM用在关键任务应用程序里,那就必须常常备份你全部的实 时数据,经过其复制特性,MYSQL可以支持这样的备份应用程序。
(3)Memory(也叫HEAP)堆内存嘛:
定义:
使用存在内存中的内容来建立表。每一个MEMORY表只实际对应一个磁盘文件。MEMORY类型的表访问很是得快,由于它的数据是放在内存中的,而且默认使用HASH索引。
可是一旦服务关闭,表中的数据就会丢失掉。 HEAP容许只驻留在内存里的临时表格。驻留在内存里让HEAP要比ISAM和MYISAM都快,可是它所管理的数据是不稳定的,并且若是在关机以前没有进行保存,那么全部的数据都会丢失。在数据行被删除的时候,HEAP也不会浪费大量的空间。HEAP表格在你须要使用SELECT表达式来选择和操控数据的时候很是有用。
适用场景:
1)那些内容变化不频繁的代码表,或者做为统计操做的中间结果表,便于高效地堆中间结果进行分析并获得最终的统计结果。
2)目标数据比较小,并且很是频繁的进行访问,在内存中存放数据,若是太大的数据会形成内存溢出。能够经过参数max_heap_table_size控制Memory表的大小,限制Memory表的最大的大小。
3)数据是临时的,并且必须当即可用获得,那么就能够放在内存中。
4)存储在Memory表中的数据若是忽然间丢失的话也没有太大的关系。
注意: Memory同时支持散列索引和B树索引,B树索引能够使用部分查询和通配查询,也能够使用<,>和>=等操做符方便数据挖掘,散列索引相等的比较快可是对于范围的比较慢不少。
特性要求:
1)要求存储的数据是数据长度不变的格式,好比,Blob和Text类型的数据不可用(长度不固定的)。
2)要记住,在用完表格以后就删除表格。
(4)Mrg_Myisam:(分表的一种方式–水平分表)
定义:
是一个相同的能够被看成一个来用的MyISAM表的集合。“相同”意味着全部表一样的列和索引信息。
也就是说,他将MyIsam引擎的多个表聚合起来,可是他的内部没有数据,真正的数据依然是MyIsam引擎的表中,可是能够直接进行查询、删除更新等操做。
好比:咱们可能会遇到这样的问题,同一种类的数据会根据数据的时间分为多个表,若是这时候进行查询的话,就会比较麻烦,Merge能够直接将多个表聚合成一个表统一查询,而后再删除Merge表(删除的是定义),原来的数据不会影响。
(5)Blackhole(黑洞引擎)
定义
任何写入到此引擎的数据均会被丢弃掉, 不作实际存储;Select语句的内容永远是空。
他会丢弃全部的插入的数据,服务器会记录下Blackhole表的日志,因此能够用于复制数据到备份数据库。
使用场景:
1)验证dump file语法的正确性
2)以使用blackhole引擎来检测binlog功能所须要的额外负载
3)充当日志服务器
其他引擎,你们感兴趣就各自先百度吧。本文主要是对比引擎使用以及其原理。
数据库的模式
# mysql 5.7 之后默认都是安全模式 # mysql 5.6 版本 sql_model=no_engine_substitution # 非安全性,默认 sql_model=strict_trans_tables # 安全性 # 查看当前数据库模式: show variables like "%sql_mode%"; # %匹配0~n个任意字符 => 模糊查询 # 临时设置为安全模式,服务重启后会被重置 mysql>: set global sql_mode="strict_trans_tables"; # 在root用户登陆状态下 # 在设置后,quit断开数据库链接后(服务器不重启)就会进入安全模式 # 安全模式下,非安全模式下sql执行的警告语句,都会抛异常 eg>: create table t1(name char(2)); eg>: insert into t1 values ("ab") # 正常 eg>: insert into t1 values ("owen") # 错误 Data too long for column 'name' at row 1
经常使用字符集
位(bit):是计算机 内部数据 储存的最小单位,11001100是一个八位二进制数。
字节(byte):是计算机中 数据处理 的基本单位,习惯上用大写 B 来表示,1B(byte,字节)= 8bit(位)
字符:是指计算机中使用的字母、数字、字和符号
ASCIIS码: 1个英文字母(不分大小写)= 1个字节的空间
1个中文汉字 = 2个字节的空间
1个ASCII码 = 一个字节
UTF-8编码:1个英文字符 = 1个字节
英文标点 = 1个字节
1个中文(含繁体) = 3个字节
中文标点 = 3个字节
Unicode编码:1个英文字符 = 2个字节
英文标点 = 2个字节
1个中文(含繁体) = 2个字节
中文标点 = 2个字节
数据存储是以“字节”(Byte)为单位,数据传输大可能是以“位”(bit,又名“比特”)为单位,一个位就表明一个0或1(即二进制),每8个位(bit,简写为b)组成一个字节(Byte,简写为B),是最小一级的信息单位。
B与iB
1KiB(Kibibyte)=1024byte
1KB(Kilobyte)=1000byte
1MiB(Mebibyte)=1048576byte
1MB(Megabyte)=1000000byte
硬盘生产商是以GB(十进制),即10的3次方=1000,如1MB=1000KB)计算的,而电脑(操做系统)是以GiB(2进制,即2的10次方, 如1MiB=1024KiB)计算的,可是国内用户通常理解为1MiB=1M=1024 KB, 因此为了便于中文化的理解,翻译MiB为MB也是能够的。
一样根据硬盘)厂商与用户对于1MB大小的不一样理解,因此好多160G的硬盘实际容量按计算机实际的1MiB=1024KB算都不到160G,这也能够解释为何新买的硬盘“缺斤短两”并无它所标示的那么大。
国际单位制(SI):
1KB=1024B;1MB=1024KB=1024×1024B。
1B(byte,字节)= 8 bit(见下文);
1KB(Kilobyte,千字节])=1024B= 2^10 B;
1MB(Megabyte,兆字节,百万字节,简称“兆”)=1024KB= 2^20 B;
1GB(Gigabyte,吉字节,十亿字节,又称“千兆”)=1024MB= 2^30 B;
1TB(Terabyte,万亿字节,太字节)=1024GB= 2^40 B;
1PB(Petabyte,千万亿字节,拍字节)=1024TB= 2^50 B;
1EB(Exabyte,百亿亿字节,艾字节)=1024PB= 2^60 B;
1ZB(Zettabyte,十万亿亿字节,泽字节) =102424EB= 2^70 B;
1YB(Yottabyte,一亿亿亿字节,尧字节)= 1024ZB= 2^80 B;
1BB(Brontobyte,一千亿亿亿字节)= 1024YB= 2^90 B;
1NB(NonaByte,一百万亿亿亿字节) = 1024BB = 2^100 B;
1DB(DoggaByte,十亿亿亿亿字节) = 1024 NB = 2^110 B;
数据存储是以10进制表示,数据传输是以2进制表示的,因此1KB不等于1000B。
-
ASCII
ASCII是7比特的字符集,涵盖了英语中的绝大多数字符。编码从0到127.
ASCII码实现的是大小写英文字母,阿拉伯数字,及经常使用的标点符、运算符、控制字符(换行、删除等)和通讯字符(文头、确认等)与计算机编码之间的对应。ASCII编码采用单字节(8 Bit)存储,实际数据存储空间是7 Bit,最高位的1 Bit是奇偶校验位。
ASCII编码对于英语国家足够用了,可是却没法表达非英语国家字符到计算机编码之间的映射,如中文汉字、法语字母等。因此,出现了不少非ASCII编码(但大多数都是兼容ASCII码的)。
-
ISOLatin-1(the ISO-8859-1 standard)
ISO Latin-1是8比特的字符集,定义了256个字符。前128个字符(00000000-01111111)与ASCII彻底一致。
Latin1是ISO-8859-1的别名,有些环境下写做Latin-1。Latin1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间彻底和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。
由于Latin1编码范围使用了单字节内的全部空间,在支持Latin1编码的系统中传输和存储其余任何编码的字节流都不会被抛弃。换言之,把其余任何编码的字节流看成Latin1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。
-
Unicode
世界上存在着多种编码方式,同一个二进制数字能够被解释成不一样的符号。所以,要想打开一个文本文件,就必须知道它的编码方式,不然用错误的编码方式解读,就会出现乱码。为何电子邮件经常出现乱码?就是由于发信人和收信人使用的编码方式不同。
能够想象,若是有一种编码,将世界上全部的符号都归入其中。每个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode。
Unicode固然是一个很大的集合,如今的规模能够容纳100多万个符号。每一个符号的编码都不同须要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
若是全部字符都按照最大存储空间存储,那必然会浪费很大的空间,好比全部字符都按照3字节存储,可是英文字母只须要一个字节存储就够了,就等于说一个Unicode编码的英文文档是ASCII编码文档存储空间的三倍。 因此,便有了变长编码—-UTF-8。
Unicode只是定义了字符的编码值,并未指定值以何种形式存储。好比汉字“田”的Unicode编码是7530,转换为二进制是01110101,00110000。比方如今定义一种unicode的实现方式UTF-FAKE,规则是
a. 使用24个字节
b. 每一个字节的高7位都是1
c. 每一个字节的最末一位存储unicode编码值
那么01110101,00110000的存储形式是
11111110, 11111110, 11111110, 11111110, 11111110, 11111110, 11111110, 11111110,
11111110, 11111111, 11111111, 11111111, 11111110, 11111111, 11111110, 11111111,
11111110, 11111110, 11111111, 11111111, 11111110, 11111110, 11111110, 11111110
其中末位为蓝色0的字节为补足字节。
实际使用的编码方式UTF-8使用三个字节存储“田” 01110101,00110000,以下
11100111, 10010100, 10110000
Unicode的第一个版本于1991年发布,该版本容许的的最大编码空间是两个字节。96年发布的Unicode 2.0版本引入了surrogate pair,将Unicode的编码数目扩充到了百万级,因为可见的未来该数目不大可能用光,所以Unicode委员会对外宣称该上限永不会更改。Surrogate pair在UTF-16和UTF-32中获得了实现。Unicode的前256个字符及编码值与Latin-1彻底一致。好比大写字母A在Latin-1和Unicode中的编码值都是0x41(十进制的65)。
Unicode的编码值范围是 000000hex 到10FFFFhex,可划分为17个plane,每一个plane包含65536(= 216)个字符。Plane的代码从0到16(十进制),对应于 000000hex,010000hex,020000hex,… … ,0F0000hex,10FFFFhex的蓝色部分。
Unicode的表示方式通常是”U+”后缀上4到6个十六进制字符,如”田“的Unicode表示方式是U+7530。
-
UTF-8
UTF-8就是在互联网上使用最广的一种Unicode的实现方式。其余实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。
UTF-8最大的一个特色,就是它是一种变长的编码方式。它能够使用1~4个字节表示一个符号,根据不一样的符号而变化字节长度。如ASCII编码的内容UTf-8中就是用一个字符存储的。
UTF-8采用可变长度的编码,长度从1到4个字节不等。某些应用识别非标准的"utf8" 或"UTF 8"别名。只有ASCII字符在UTF-8中使用一个字节编码,且值与ASCII彻底相同,其他字符在UTF-8中使用2到4个字节。所以UTF-8中的单字节且只有单字节编码字符的最高的1个比特是0。
UTF-8对Unicode字符的编码规则以下
说明以下:
-
只有ASCII使用单字节编码
-
Unicode编码值大于127的字符使用多个字节编码。多字节序列的第一个字节称为leading byte,后续的字节称为continuation bytes。Leading byte的高位是110,1110或11110,其中的“1”的个数标明了序列中的字节总数。如2个字节序列的leading byte为110xxxxx,其中的11标明了这是一个双字节的序列,亦即该序列有1个continuation byte。Continuation bytes的每一个字节的高两位均是10。
-
单字节序列、leading bytes和continuationbytes的高位分别是0,110/1110/11110和10,所以不会混淆。
仍是以汉字”田“为例,展现Unicode字符如何按照UTF-8存储。”田“的Unicode值是U+7530,比对上表发现介于U+0800 - U+FFFF之间,所以须要3个字节来存储。7530转为二进制是1110101,00110000,一共15位。但因为UTF-8的3字节编码存储16个比特,所以将1110101,00110000的高一位补零变成16比特01110101,00110000。而后将这16比特依次填入三字节序列1110xxxx 10xxxxxx 10xxxxxx的x中,获得结果
11100111 10010100 10110000,写成16进制就是E7 94 B0
注意:虽然Unicode中的前256个字符及编码值与Latin-1彻底一致,但UTF-8只对前128个即ASCII字符采用单字节编码,其他128个Latin-1字符是采用2个字节编码。所以ASCII编码的文件能够直接以UTF-8方式读取,而Latin-1的文件若包含值为128-255的字符则不能够。
UTF-8是一种变长字节编码方式。对于某一个字符的UTF-8编码,若是只有一个字节则其最高二进制位为0;若是是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其他各字节均以10开头。UTF-8最多可用到6个字节。 如表: 1字节 0xxxxxxx 2字节 110xxxxx 10xxxxxx 3字节 1110xxxx 10xxxxxx 10xxxxxx 4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx Unicode
UNICODE UTF8转换规则
符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
下面,仍是以汉字“严”为例,演示如何实现UTF-8编码。
下面,仍是以汉字“严”为例,演示如何实现UTF-8编码。
已知“严”的unicode是4E25(100111000100101),根据上表,能够发现4E25处在第三行的范围内(0000 0800-0000 FFFF),所以“严”的UTF-8编码须要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。而后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就获得了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。
-
-
UTF-16
UTF-16也是采用可变长度编码,能够是一个或者两个16比特。某些应用中容许使用非标准的UTF_16或者UTF16做为别名。Unicode中的第一个plane的65536(= 216)codepoints采用16比特编码,其他的16个plane均采用2个16比特编码。采用2个16比特编码的先后两个16bit分别称为lead surrogate pair和trail surrogate pair,之因此称为surrogate是由于单独一个16bit不表明任何字符,只有组合起来才有意义。
既然UTF-16也是可变长度编码,如何区分某个16bit是单独表示一个字符仍是与后续的16bit组合起来表示一个字符呢?Unicode将D800–DBFF和DC00–DFFF这两个范围做为保留区间,没有将之分配给任何Unicode字符,若某16比特落在D800–DBFF范围内,即可将之视为采用2个16bit编码字符的第一个16bit,而落在DC00–DFFF的16bit可视为采用2个16bit编码字符的第二个16bit。这就使得Unicode第一个plane实际可分配使用的code points只有65536 – (DFFF - D800 + 1) = 65536 – 8*256 = 63488。
采用一个16bit编码的Unicode字符在UTF-16中的编码值与其在Unicode中是相等的,好比英文大写字母A的Unicode值是U+0041,其UTF-16编码是0041 hex 。Unicode第二到第十七个plane采用两个16bit即surrogate pairs的字符从其Unicode code point到UTF-16的转换规则是
-
范围为0x10000 … 0x10FFFF的codepoint减去0x010000,减事后的结果范围是0x00000到0xFFFFF,使得该结果能够使用5位16进制亦即20位2进制数表示
-
结果中高10位(范围是0x0到0x3FF)加上0xD800(结果范围是0xD800到0xDBFF)做为双16bit的第一个16bit即leadsurrogate
-
结果中低10位(范围是0x0到0x3FF)加上0xDC00(结果范围是0xDC00到0xDFFF)做为双16bit的第二个16bit即trailsurrogate
这样UTF-16与UTF-8都是self-synchronizing的,即某个16bit是不是一个字符的开始无需检查其前一个或者后一个16bit。与UTF-8的不一样之处是,UTF-16不支持从某个随机的字节开始读取。
举例:UTF-16 序列 0041, D801DC01 (字符"A"),若第一个字节丢失即从第二个字节读取,那么UTF-16认为序列是41D8,01DC,01;而UTF-8不存在这个问题。
-
-
GKB
GBK 是又一个汉字编码标准,全称《汉字内码扩展规范》(GBK),英文名称 Chinese Internal Code Specification ,中华人民共和国全国信息技术标准化技术委员会 1995 年 12 月 1 日制订,国家技术监督局标准化司、电子工业部科技与质量监督司 1995 年 12 月 15 日联合以技监标函 [1995] 229 号文件的形式,将它肯定为技术规范指导性文件,发布和实施。这一版的 GBK 规范为 1.0 版。GB 即“国标”,K 是“扩展”的汉语拼音第一个字母。
GBK 向下与 GB 2312 编码兼容,向上支持 ISO 10646.1 国际标准,是前者向后者过渡过程当中的一个承上启下的标准。 ISO 10646 是国际标准化组织 ISO 公布的一个编码标准,即 Universal Multilpe-Octet Coded Character Set(简称 UCS),大陆译为《通用多八位编码字符集》,台湾译为《广用多八位元编码字元集》,它与 Unicode 组织的 Unicode 编码彻底兼容。ISO 10646.1 是该标准的第一部分《体系结构与基本多文种平面》。我国 1993 年以 GB 13000.1 国家标准的形式予以承认(即 GB 13000.1 等同于 ISO 10646.1)。 ISO 10646 是一个包括世界上各类语言的书面形式以及附加符号的编码体系。其中的汉字部分称为“CJK 统一汉字”(C 指中国,J 指日本,K 指朝鲜)。而其中的中国部分,包括了源自中国大陆的 GB 23十二、GB 1234五、《现代汉语通用字表》等法定标准的汉字和符号,以及源自台湾的 CNS 11643 标准中第 一、2 字面(基本等同于 BIG-5 编码)、第 14 字面的汉字和符号。
1、字汇 GBK 规范收录了 ISO 10646.1 中的所有 CJK 汉字和符号,并有所补充。具体包括:
- GB 2312 中的所有汉字、非汉字符号。
- GB 13000.1 中的其余 CJK 汉字。以上合计 20902 个 GB 化汉字。
- 《简化字总表》中未收入 GB 13000.1 的 52 个汉字。
- 《康熙字典》及《辞海》中未收入 GB 13000.1 的 28 个部首及重要构件。
- 13 个汉字结构符。
- BIG-5 中未被 GB 2312 收入、但存在于 GB 13000.1 中的 139 个图形符号。
- GB 12345 增补的 6 个拼音符号。
- 汉字“○”。
- GB 12345 增补的 19 个竖排标点符号(GB 12345 较 GB 2312 增补竖排标点符号 29 个,其中 10 个未被 GB 13000.1 收入,故 GBK 亦不收)。
- 从 GB 13000.1 的 CJK 兼容区挑选出的 21 个汉字。
- GB 13000.1 收入的 31 个 IBM OS/2 专用符号。
2、码位分配及顺序 GBK 亦采用双字节表示,整体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。总计 23940 个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。 所有编码分为三大部分:
-
汉字区。包括: a. GB 2312 汉字区。即 GBK/2: B0A1-F7FE。收录 GB 2312 汉字 6763 个,按原顺序排列。 b. GB 13000.1 扩充汉字区。包括: (1) GBK/3: 8140-A0FE。收录 GB 13000.1 中的 CJK 汉字 6080 个。 (2) GBK/4: AA40-FEA0。收录 CJK 汉字和增补的汉字 8160 个。CJK 汉字在前,按 UCS 代码大小排列;增补的汉字(包括部首和构件)在后,按《康熙字典》的页码/字位排列。
-
图形符号区。包括: a. GB 2312 非汉字符号区。即 GBK/1: A1A1-A9FE。其中除 GB 2312 的符号外,还有 10 个小写罗马数字和 GB 12345 增补的符号。计符号 717 个。 b. GB 13000.1 扩充非汉字区。即 GBK/5: A840-A9A0。BIG-5 非汉字符号、结构符和“○”排列在此区。计符号 166 个。
-
用户自定义区:分为(1)(2)(3)三个小区。 (1) AAA1-AFFE,码位 564 个。 (2) F8A1-FEFE,码位 658 个。 (3) A140-A7A0,码位 672 个。 第(3)区尽管对用户开放,但限制使用,由于不排除将来在此区域增补新字符的可能性。
3、字形 GBK 对字形做了以下的规定:
- 原则上与 GB 13000.1 G列(即源自中国大陆法定标准的汉字)下的字形/笔形保持一致。
- 在 CJK 汉字认同规则的总框架内,对全部的 GBK 编码汉字实施“无重码正形”(“GB 化”);即在不形成重码的前提下,尽可能采用中国新字形。
- 对于超出 CJK 汉字认同规则的、或认同规则还没有明确规定的汉字,在 GBK 码位上暂安放旧字形。这样,在许多状况下 GBK 收入了同一汉字的新旧两种字形。
- 非汉字符号的字形,凡 GB 2312 已经包括的,与 GB 2312 保持一致;超出 GB 2312 的部分,与 GB 13000.1 保持一致。
- 带声调的拼音字母取半角形式。
GBK编码是在GB2312-80(也称做GB2312,GB码)标准基础上的内码扩展规范,使用了双字节编码方案。
GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示,为了区分中文,将其最高位都设定成1。GBK包含所有中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大
GBK、GB2312等与UTF8之间都必须经过Unicode编码才能相互转换:
GBK、GB2312<= = =>Unicode<= = =>UTF8
补充:
GB2312 最先一版的中文编码,每一个字占据2bytes。因为要和ASCII兼容,那这2bytes最高位不能够为0 了(不然和ASCII会有冲突)。在GB2312中收录了6763个汉字以及682个特殊符号,已经囊括了生活中最 经常使用的全部汉字。
GBK 因为GB2312只有6763个汉字,我汉语博大精深,只有6763个字怎么够?因而GBK中在保证不和 GB23十二、ASCII冲突(即兼容GB2312和ASCII)的前提下,也用每一个字占据2bytes的方式又编码了许多 汉字。通过GBK编码后,能够表示的汉字达到了20902个,另有984个汉语标点符号、部首等。值得注意 的是这20902个汉字还包含了繁体字。
GB18030 然而,GBK的两万多字也已经没法知足咱们的需求了,还有更多可能你本身历来没见过的汉字 须要编码。这时候显然只用2bytes表示一个字已经不够用了(2bytes最多只有65536种组合,然而为了和 ASCII兼容,最高位不能为0就已经直接淘汰了一半的组合,只剩下3万多种组合没法知足所有汉字求)。 所以GB18030多出来的汉字使用4bytes编码。固然,为了兼容GBK,这个四字节的前两位显然不能与 GBK冲突(实操中发现后两位也并无和GBK冲突)。我国在2000年和2005年分别颁布的两次GB18030 编码,其中2005年的是在2000年基础上进一步补充。至此,GB18030编码的中文文件已经有七万多个汉 字了,甚至包含了少数民族文字。
这图中展现了前文所述的几种编码在编码完成后,前2个byte的值的范围(用16进制表示)。每一个byte能够表 示00到FF(即0至255)。从图中咱们能够一目了然地看到为何GB18030能够兼容GBK,GB2312和ASCII 了。他们几种编码之间前两位没有重合部分。须要注意的是ASCII只有1byte,因此是没有第二位的。另外 GB18030在上图中占的面积虽然很小,可是它是4bytes编码,这图只展现了前两位。若是后两位也算上, GB18030的字数要远多于GBK。另外须要注意的是,因为GBK兼容GB2312,所以属于GB2312的蓝色区域其 实也能够算做是GBK的区域。同理GBK的区域理论上也属于GB18030的区域。上表中只是展现了多出来的部 分。
实际生活中,咱们用到的99%以上的汉字,其实都在GB2312那一块区域内。至于GB2312每一个编码对应的到 底是哪一个汉字本文再也不赘述,能够参考连接(连接地址)查询。GBK编码所对应的汉字能够参考连接 (连接地址)查询。至于GB18030编码,因为字数实在太多太难写,已经很难在网上找到在线的编码全表 了。不过通过一番搜寻,仍是找到了我国发布GB18030编码时的相关文档(GB18030-2005文档、 GB18030-2000文档)。
在实际使用中,GBK编码已经能够知足大部分场景了,GB18030编码中全部汉字都是咱们这辈子都不必定能 见到的文字,这也是平时为何常常会使用GBK的缘由吧。
表的基本操做
##前提:先选取要操做的数据库 1)查看已有表 mysql>:show tables; 2)建立表 mysql>:create table 表名(字段1 类型, ..., 字段n 类型); eg>: create table student(name varchar(16), age int); eg>: create table teacher(name varchar(16), age int); 3)查看建立表的sql mysql>:show create table 表名; eg>: show create table student; 4)查看建立表的结构 mysql>:desc 表名; 5)改表结构 # 修改表名 mysql>: alter table 旧表 rename 新表; # 修改字段名 mysql>: alter table 表名 change 旧字段 新字段 类型(长度); # 修改字段属性 mysql>: alter table 表名 modify 字段 新类型(长度); 6)删除表 mysql>: drop table 表名; eg>: drop table teacher;
建立表的完整语法
# 长度和约束在某些状况下是能够省略的 mysql>: create table 表名 ( 属性名1 类型(长度) 约束, ... 属性名n 类型(长度) 约束 ) engine=引擎 default charset=utf8;
记录的基本操做
1)查看某个数据库中的某个表的全部记录,若是在对应数据库中,能够直接查找表 mysql>: select * from [数据库名.]表名; 注:*表明查询全部字段 2)给表的全部字段插入数据 mysql>: insert [into] [数据库名.]表名 values (值1,...,值n); eg:若是给有name和age两个字段的student表插入数据 1条>:insert into student values ('Bob', 18); 多条>:insert into student values ('张三', 18),('李四', 20); 指定库>:insert owen.student values ('张三', 18),('李四', 20); 3)根据条件修改指定内容 mysql>: update [数据库名.]表名 set 字段1=新值1, 字段n=新值n where 字段=旧值; eg:> update student set name='王五', age='100' where name='张三'; 注:i) 能够只修改部分字段 ii) 没有条件下,全部记录都会被更新 eg:> update student set name='呵呵'; 4)根据条件删除记录 mysql>: delete from [数据库名.]表名 where 条件; eg:> delete from student where age<30;
sql函数
函数及描述 NOW():返回当前的日期和时间 CURDATE():返回当前的日期 CURTIME():返回当前的时间 DATE():提取日期或日期/时间表达式的日期部分 EXTRACT():返回日期/时间按的单独部分 DATE_ADD():给日期添加指定的时间间隔 DATE_SUB():从日期减去指定的时间间隔 DATEDIFF():返回两个日期之间的天数 DATE_FORMAT():用不一样的格式显示日期/时间
mysql支持的数据类型
# mysql数据库支持存放哪些数据 # 整型 | 浮点型 | 字符型 | 时间类型 | 枚举类型 | 集合类型
整型
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT | 1 字节 | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 字节 | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT | 3 字节 | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 字节 | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT | 8 字节 | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
'''约束 unsigned:无符号 zerofill:0填充 ''' 3位 1 001 # 建表 mysql>: create table tb1(x tinyint, y smallint, z int(6)); # 插入数据 mysql>: insert into tb1 values(128, 32768, 32768); # 结果:127,32767,32768 # 结论:整型的长度由所占字节(取值范围)决定,能够自定义长度,可是不影响所占字节(取值范围) # 全部整型变量的长度通常都省略不写,不一样类型所占字节数不同, 决定所占空间及存放数据的大小限制 结论>: create table tb1(x tinyint, y smallint, z int); # 整型约束 mysql>: create table tb2(x tinyint unsigned); # 0~255 mysql>: insert into tb2 values(256), (-1); # 255, 0 # 0填充约束 mysql>: create table tb3(x tinyint unsigned zerofill); mysql>: insert into tb3 values(10); # 010 '''宽度 1.不能决定整型存放数据的宽度, 超过宽度能够存放, 最终由数据类型所占字节决定 2.若是没有超过宽度,且有zerofill限制, 会用0填充前置位的不足位 3.没有必要规定整型的宽度, 默认设置的宽度就为该整型能存放数据的最大宽度 * '''
浮点型
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
FLOAT | 4 字节 | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE | 8 字节 | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
DECIMAL | 对DECIMAL(M,D) ,若是M>D,为M+2不然为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
# 在安全模式下测试浮点型类型 '''类型 float(M, D):4字节,3.4E–38~3.4E+38 double(M, D):8字节,1.7E–308~1.7E+308 decimal(M, D):所在字节M,D大值基础上+2,其实就是M值+2就是decimal字段所占字节数,(M, D) => M为位数,D为小数位 ''' '''宽度: 限制存储宽度 (M, D) => M为位数,D为小数位,M要大于等于D float(255, 30):精度最低,最经常使用 double(255, 30):精度高,占位多 decimal(65, 30):字符串存,全精度 ''' # 建表: mysql>: create table tb4 (age float(256, 30)); # Display width out of range for column 'age' (max = 255) mysql>: create table tb5 (age float(255, 31)); # Too big scale 31 specified for column 'age'. Maximum is 30. mysql>: create table tb5 (age float(65, 30)); # 在合理取值范围 mysql>: create table t12 (x float(255, 30)); mysql>: create table t13 (x double(255, 30)); mysql>: create table t14 (x decimal(65, 30)); # 1.111111164093017600000000000000 mysql>: insert into t12 values(1.11111111111111111119); # 1.111111111111111200000000000000 mysql>: insert into t13 values(1.11111111111111111119); # 1.111111111111111111190000000000 mysql>: insert into t14 values(1.11111111111111111119); # 重点:长度与小数位分析 # 报错,总长度M必须大于等于小数位D mysql>: create table t14 (x decimal(2, 3)); # 能存储 -0.9999 mysql>: create table t14 (x decimal(3, 3));
字符串:
数据库优化 - char效率要高于varchar
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255字节 | 定长字符串 |
VARCHAR | 0-65535 字节 | 变长字符串 |
TINYBLOB | 0-255字节 | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255字节 | 短文本字符串 |
BLOB | 0-65 535字节 | 二进制形式的长文本数据 |
TEXT | 0-65 535字节 | 长文本数据 |
MEDIUMBLOB | 0-16 777 215字节 | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215字节 | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295字节 | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295字节 | 极大文本数据 |
CHAR 和 VARCHAR 类型相似,但它们保存和检索的方式不一样。它们的最大长度和是否尾部空格被保留等方面 也不一样。在存储或检索过程当中不进行大小写转换。
BINARY 和 VARBINARY 相似于 CHAR 和 VARCHAR,不一样的是它们包含二进制字符串而不要非二进制字符 串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,而且排序和比较基于列值 字节的数值值。
BLOB 是一个二进制大对象,能够容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、 MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不一样。
有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的 最大长度不一样,可根据实际状况选择。
'''类型 char:定长 varchar:不定长 ''' '''宽度 限制存储宽度 char(4):以4个字符存储定长存储数据 varchar(4):数据长度决定字符长度,为可变长度存储数据 ''' # eg: create table t15 (x char(4), y varchar(4)); insert into t15 values("zero", 'owen'); # '' | "" 都可以表示字符 select x,y from t15; # 正常 insert into t15 values("yanghuhu", 'lxxVSegon'); # 非安全模式数据丢失,能够存放, 安全模式报错 select x,y from t15; # 能够正常显示丢失后(不完整)的数据 insert into t15 values('a', 'b'); # 验证数据所在字符长度 # 前提: 安全模式下以空白填充字符 set global sql_mode="strict_trans_tables,PAD_CHAR_TO_FULL_LENGTH"; # 重启链接 select char_length(x), char_length(y) from t15; # a占4 b占1 '''重点: 存储数据的方式 ** => 数据库优化 char: 必定按规定的宽度存放数据, 以规定宽度读取数据, 一般更占空间 varchar: 首先根据数据长度计算所需宽度, 并在数据开始以数据头方式将宽度信息保存起来, 是一个计算耗时过程, 取先读取宽度信息,以宽度信息为依准读取数据, 一般节省空间 ''' 8: zero egon lxx yanghuhu 8: 4zero4egon3lxx8yanghuhu 注: varchar的数据头占1~2字节 规定char|varchar宽度均为4,用来存放4个字符的数据, char存取更高效,char占4字符,varchar占5字符,char更省空间 总结: 数据长度相近的数据提倡用char来存放数据, 数据须要高速存取,以空间换时间, 采用char
时间
每一个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
类型 | 大小 (字节) | 范围 | 格式 | 用途 |
---|---|---|---|---|
DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3 | '-838:59:59'/'838:59:59' | HH:MM:SS | 时间值或持续时间 |
YEAR | 1 | 1901/2155 | YYYY | 年份值 |
DATETIME | 8 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
TIMESTAMP | 4 | 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
'''类型 year:yyyy(1901/2155) date:yyyy-MM-dd(1000-01-01/9999-12-31) time:HH:mm:ss datetime:yyyy-MM-dd HH:mm:ss(1000-01-01 00:00:00/9999-12-31 23:59:59) timestamp:yyyy-MM-dd HH:mm:ss(1970-01-01 00:00:00/2038-01-19 ??) ''' # eg: 1 create table t16(my_year year, my_date date, my_time time); insert into t16 values(); # 三个时间类型的默认值均是null insert into t16 values(2156, null, null); # 在时间范围外,不容许插入该数据 insert into t16 values(1, '2000-01-01 12:00:00', null); # 2001 2000-01-01 null insert into t16 values(2019, '2019-01-08', "15-19-30"); # time报格式错误 => 按照时间规定格式存放数据 alter table t16 change my_year myYear year(2); # 时间的宽度修改后仍是采用默认宽度 => 不须要关系宽度 # eg:2 create table t17(my_datetime datetime, my_timestamp timestamp); insert into t17 values(null, null); # 能够为空, 不能为null,赋值null采用默认值current_timestamp insert into t17 values('4000-01-01 12:00:00', '2000-01-01 12:00:00'); # 在各自范围内能够插入对应格式的时间数据 # datetime VS timestamp datetime:时间范围,不依赖当前时区,8字节,能够为null timestamp:时间范围,依赖当前时区,4字节,有默认值CURRENT_TIMESTAMP
二进制数据(_Blob)
1._BLOB和_text存储方式不一样,_TEXT以文本方式存储,英文存储区分大小写,而_Blob是以二进制方式存储,不 分大小写。
2._BLOB存储的数据只能总体读出。
3._TEXT能够指定字符集,_BLO不用指定字符集。
MYSQL数据类型的长度和范围
各数据类型及字节长度一览表:
数据类型 | 字节长度 | 范围或用法 |
---|---|---|
Bit | 1 | 无符号[0,255],有符号[-128,127],天缘博客备注:BIT和BOOL布尔型都占用1字节 |
TinyInt | 1 | 整数[0,255] |
SmallInt | 2 | 无符号[0,65535],有符号[-32768,32767] |
MediumInt | 3 | 无符号[0,2^24-1],有符号[-2^23,2^23-1]] |
Int | 4 | 无符号[0,2^32-1],有符号[-2^31,2^31-1] |
BigInt | 8 | 无符号[0,2^64-1],有符号[-2^63 ,2^63 -1] |
Float(M,D) | 4 | 单精度浮点数。天缘博客提醒这里的D是精度,若是D<=24则为默认的FLOAT,若是D>24则会自动被转换为DOUBLE型。 |
Double(M,D) | 8 | 双精度浮点。 |
Decimal(M,D) | M+1或M+2 | 未打包的浮点数,用法相似于FLOAT和DOUBLE,天缘博客提醒您若是在ASP中使用到Decimal数据类型,直接从数据库读出来的Decimal可能须要先转换成Float或Double类型后再进行运算。 |
Date | 3 | 以YYYY-MM-DD的格式显示,好比:2009-07-19 |
Date Time | 8 | 以YYYY-MM-DD HH:MM:SS的格式显示,好比:2009-07-19 11:22:30 |
TimeStamp | 4 | 以YYYY-MM-DD的格式显示,好比:2009-07-19 |
Time | 3 | 以HH:MM:SS的格式显示。好比:11:22:30 |
Year | 1 | 以YYYY的格式显示。好比:2009 |
Char(M) | M | 定长字符串。 |
VarChar(M) | M | 变长字符串,要求M<=255 |
Binary(M) | M | 相似Char的二进制存储,特色是插入定长不足补0 |
VarBinary(M) | M | 相似VarChar的变长二进制存储,特色是定长不补0 |
Tiny Text | Max:255 | 大小写不敏感 |
Text | Max:64K | 大小写不敏感 |
Medium Text | Max:16M | 大小写不敏感 |
Long Text | Max:4G | 大小写不敏感 |
TinyBlob | Max:255 | 大小写敏感 |
Blob | Max:64K | 大小写敏感 |
MediumBlob | Max:16M | 大小写敏感 |
LongBlob | Max:4G | 大小写敏感 |
Enum | 1或2 | 最大可达65535个不一样的枚举值 |
Set | 可达8 | 最大可达64个不一样的值 |
Geometry | ||
Point | ||
LineString | ||
Polygon | ||
MultiPoint | ||
MultiLineString | ||
MultiPolygon | ||
GeometryCollection |
使用建议
一、在指定数据类型的时候通常是采用从小原则,好比能用TINY INT的最好就不用INT,能用FLOAT类型的就 不用DOUBLE类型,这样会对MYSQL在运行效率上提升很大,尤为是大数据量测试条件下。
二、不须要把数据表设计的太过复杂,功能模块上区分或许对于后期的维护更为方便,慎重出现大杂烩数据表
三、数据表和字段的起名字也是一门学问
四、设计数据表结构以前请先想象一下是你的房间,或许结果会更加合理、高效
五、数据库的最后设计结果必定是效率和可扩展性的折中,偏向任何一方都是欠妥的
选择数据类型的基本原则
前提:使用适合存储引擎。
选择原则:根据选定的存储引擎,肯定如何选择合适的数据类型。
下面的选择方法按存储引擎分类:
- MyISAM 数据存储引擎和数据列:MyISAM数据表,最好使用固定长度(CHAR)的数据列代替可变长度(VARCHAR)的数据列。
- MEMORY存储引擎和数据列:MEMORY数据表目前都使用固定长度的数据行存储,所以不管使用CHAR或VARCHAR列都没有关系。二者都是做为CHAR类型处理的。
- InnoDB 存储引擎和数据列:建议使用 VARCHAR类型。
对于InnoDB数据表,内部的行存储格式没有区分固定长度和可变长度列(全部数据行都使用指向数据列值的头指针),所以在本质上,使用固定长度的CHAR列不必定比使用可变长度VARCHAR列简单。于是,主要的性能因素是数据行使用的存储总量。因为CHAR平均占用的空间多于VARCHAR,因 此使用VARCHAR来最小化须要处理的数据行的存储总量和磁盘I/O是比较好的。
下面说一下固定长度数据列与可变长度的数据列。
char与varchar
CHAR和VARCHAR类型相似,但它们保存和检索的方式不一样。它们的最大长度和是否尾部空格被保留等方面也不一样。在存储或检索过程当中不进行大小写转换。
下面的表显示了将各类字符串值保存到CHAR(4)和VARCHAR(4)列后的结果,说明了CHAR和VARCHAR之间的差异:
值 | CHAR(4) | 存储需求 | VARCHAR(4) | 存储需求 |
---|---|---|---|---|
'' | ' ' | 4个字节 | '' | 1个字节 |
'ab' | 'ab ' | 4个字节 | 'ab ' | 3个字节 |
'abcd' | 'abcd' | 4个字节 | 'abcd' | 5个字节 |
'abcdefgh' | 'abcd' | 4个字节 | 'abcd' | 5个字节 |
请注意上表中最后一行的值只适用不使用严格模式时;若是MySQL运行在严格模式,超过列长度不的值不保存,而且会出现错误。
从CHAR(4)和VARCHAR(4)列检索的值并不老是相同,由于检索时从CHAR列删除了尾部的空格。经过下面的例子说明该差异: mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4)); Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO vc VALUES ('ab ', 'ab '); Query OK, 1 row affected (0.00 sec)
mysql> SELECT CONCAT(v, '+'), CONCAT(c, '+') FROM vc; +----------------+----------------+ | CONCAT(v, '+') | CONCAT(c, '+') | +----------------+----------------+ | ab + | ab+ | +----------------+----------------+ 1 row in set (0.00 sec)
text和blob
在使用text和blob字段类型时要注意如下几点,以便更好的发挥数据库的性能。
①BLOB和TEXT值也会引发本身的一些问题,特别是执行了大量的删除或更新操做的时候。删除这种值会在数据表中留下很大的"空洞",之后填入这些"空洞"的记录可能长度不一样,为了提升性能,建议按期使用 OPTIMIZE TABLE 功能对这类表进行碎片整理.
②使用合成的(synthetic)索引。合成的索引列在某些时候是有用的。一种办法是根据其它的列的内容创建一个散列值,并把这个值存储在单独的数据列中。接下来你就能够经过检索散列值找到数据行了。可是,咱们要注意这种技术只能用于精确匹配的查询(散列值对于相似<或>=等范围搜索操做符 是没有用处的)。咱们能够使用MD5()函数生成散列值,也能够使用SHA1()或CRC32(),或者使用本身的应用程序逻辑来计算散列值。请记住数值型散列值能够很高效率地存储。一样,若是散列算法生成的字符串带有尾部空格,就不要把它们存储在CHAR或VARCHAR列中,它们会受到尾部空格去除的影响。
合成的散列索引对于那些BLOB或TEXT数据列特别有用。用散列标识符值查找的速度比搜索BLOB列自己的速度快不少。
③在没必要要的时候避免检索大型的BLOB或TEXT值。例如,SELECT *查询就不是很好的想法,除非你可以肯定做为约束条件的WHERE子句只会找到所须要的数据行。不然,你可能毫无目的地在网络上传输大量的值。这也是 BLOB或TEXT标识符信息存储在合成的索引列中对咱们有所帮助的例子。你能够搜索索引列,决定那些须要的数据行,而后从合格的数据行中检索BLOB或 TEXT值。
④把BLOB或TEXT列分离到单独的表中。在某些环境中,若是把这些数据列移动到第二张数据表中,可让你把原数据表中 的数据列转换为固定长度的数据行格式,那么它就是有意义的。这会减小主表中的碎片,使你获得固定长度数据行的性能优点。它还使你在主数据表上运行 SELECT *查询的时候不会经过网络传输大量的BLOB或TEXT值。
浮点数与定点数
为了可以引发你们的重视,在介绍浮点数与定点数之前先让你们看一个例子: mysql> CREATE TABLE test (c1 float(10,2),c2 decimal(10,2)); Query OK, 0 rows affected (0.29 sec)
mysql> insert into test values(131072.32,131072.32); Query OK, 1 row affected (0.07 sec)
mysql> select * from test; +-----------+-----------+ | c1 | c2 | +-----------+-----------+ | 131072.31 | 131072.32 | +-----------+-----------+ 1 row in set (0.00 sec)
从上面的例子中咱们看到c1列的值由131072.32变成了131072.31,这就是浮点数的不精确性形成的。
在mysql中float、double(或real)是浮点数,decimal(或numberic)是定点数。
浮点数相对于定点数的优势是在长度必定的状况下,浮点数可以表示更大的数据范围;它的缺点是会引发精度问题。在从此关于浮点数和定点数的应用中,你们要记住如下几点:
- 浮点数存在偏差问题;
- 对货币等对精度敏感的数据,应该用定点数表示或存储;
- 编程中,若是用到浮点数,要特别注意偏差问题,并尽可能避免作浮点数比较;
- 要注意浮点数中一些特殊值的处理。
补充
一、一个汉字占多少长度与编码有关:
UTF-8:一个汉字=3个字节
GBK:一个汉字=2个字节
二、varchar(n) 表示 n 个字符,不管汉字和英文,Mysql 都能存入 n 个字符,仅是实际字节长度有所区别
三、MySQL 检查长度,可用 SQL 语言来查看:
select LENGTH(字段名) from 表名
枚举与集合
枚举类型,enum
每一个枚举值均有一个索引值:
在列说明中列表值所容许的成员值被从 1 开始编号。
通常来讲就是单选,在定义枚举的时候列出全部的可能性;
代码以下
1. create table type_enum( 2. gender enum('male','remale','serect'), 3. ); 4. insert into type_enum values ('remale');
在处理时,相似字符串型进行操做!
意义在于:
1, 限定值的可能性!
2, 速度快,比普通的字符串速度快!
缘由是枚举型 是利用 整数进行管理的,可以2个字节进行管理!
每一个值,都是一个整数标识,从第一个选项开始为1,逐一递增!
管理时整数的形式,速度比字符串快!
一共有2 个字节,0-65535,所以能够有 65535个选项能够使用!、
集合 set 不定想项选
相似于 enum枚举,在定义时,也须要指定其已有值!
与字符串相比,优点是:
1, 也是采用 整数进行管理的!采用位运算,从第一位开始为1,逐一x2!
2, 每一个集合类型8个字节,64位,所以能够表示64个元素!
注意:站在 mysql的角度,尽可能多用枚举和集合!
扩展:
集合 set 扩展
在建立表时,就指定SET类型的取值范围。
属性名 SET('值1','值2','值3'...,'值n')
其中,“属性名”参数指字段的名称;“值n”参数表示列表中的第n个值,这些值末尾的空格将会被系统直接删除。其基本形式与ENUM类型同样。SET类型的值能够取列表中的一个元素或者多个元素的组合。取多个元素时,不一样元素之间用逗号隔开。SET类型的值最多只能是有64个元素构成的组合,根据成员的不一样,存储上也有所不一样:
1~8成员的集合,占1个字节。 9~16成员的集合,占2个字节。 17~24成员的集合,占3个字节。 25~32成员的集合,占4个字节。 33~64成员的集合,占8个字节。
同ENUM类型同样,列表中的每一个值都有一个顺序排列的编号。MySQL中存入的是这个编号,而不是列表中的值。
插入记录时,SET字段中的元素顺序可有可无。存入MySQL数据库后,数据库系统会自动按照定义时的顺序显示。若是插入的成员中有重复,则只存储一次。
枚举类型,enum扩展
ENUM类型(枚举类型),与C#的概念同样,在定义时指定取值范围。
ENUM类型的值范围须要在建立表时经过枚举方式显式指定,对1~255个成员的枚举须要1个字节存储;对于256~65535个成员,须要2个字节存储。最多能够有65535个成员,而SET类型最多只能包含64个成员。二者的取值只能在成员列表中选取。ENUM类型只能从成员中选择一个,而SET类型能够选择多个。
所以,对于多个值中选取一个的,能够选择ENUM类型。例如,“性别”字段就能够定义成ENUM类型,由于只能在“男”和“女”中选其中一个。对于能够选取多个值的字段,能够选择SET类型。例如,“爱好”字段就能够选择SET类型,由于可能有多种爱好。
属性名 ENUM('值1','值2','值3'...'值n')
◆其中,属性名参数指字段的名称;“值n”参数表示列表中的第n个值,这些值末尾的空格将会被系统直接删除。ENUM类型的值只能取列表中的一个元素。其取值列表中最多能有65535个值。列表中的每一个值都有一个顺序排列的编号,MySQL中存入的是这个编号,而不是列表中的值。
◆ENUM 有 NOT NULL 属性,其默认值为取值列表的第一个元素; ◆ENUM 无 NOT NULL,则ENUM类型将容许插入NULL,而且NULL为默认值;
CREATE TABLE Test4(Sex ENUM('男','女')); INSERT INTO Test4 VALUES('男'); INSERT INTO Test4 VALUES('爷'); --这行报错 SELECT * FROM Test4;
ENUM 是一个字符串对象,其值一般选自一个容许值列表中,该列表在表建立时的列规格说明中被明确地列举。
在下列某些状况下,值也能够是空串('') 或 NULL: ◆若是将一个无效值插入一个 ENUM (即,一个不在容许值列表中的字符串),空字符串将做为一个特殊的错误值被插入。事实上,这个字符串有别于一个'普通的'空字符串,由于这个字符串有个数字索引值为 0。稍后有更详细描述。 ◆若是一个 ENUM 被声明为 NULL,NULL 也是该列的一个合法值,而且该列的缺省值也将为 NULL 。若是一个 ENUM 被声明为 NOT NULL,该列的缺省值将是该列表所容许值的第一个成员。
每一个枚举值均有一个索引值: ◆在列说明中列表值所容许的成员值被从 1 开始编号。 ◆空字符串错误值的索引值为 0。这就意味着,你能够使用下面所示的 SELECT 语句找出被赋于无效 ENUM值的记录行。 mysql> SELECT * FROM tbl_name WHERE enum_col=0; ◆NULL 值的索引值为 NULL。
例如,指定为 ENUM('one', 'two', 'three') 的一个列,能够有下面所显示的任一值。每一个值的索引值也以下所示:
值 | 索引值 |
---|---|
NULL | NULL |
'' | 0 |
'one' | 1 |
'two' | 2 |
'three' | 3 |
换个枚举最大能够有 65535 个成员值。
从 MySQL 3.23.51 开始,当表被建立时,ENUM 值尾部的空格将会自动删除。
当为一个 ENUM 列赋值时,字母的大小写是可有可无的。然而,之后从列中检索出来的值的大小写倒是匹配于建立表时所指定的容许值。
若是在一个数字语境中检索一个ENUM,列值的索引值将被返回。例如,你能够像这样使用数字值检索一个 ENUM 列:
mysql> SELECT enum_col+0 FROM tbl_name;
若是将一个数字存储到一个 ENUM 中,数字被看成为一个索引值,而且存储的值是该索引值所对应的枚举成员。(可是,这在 LOAD DATA 将不能工做,由于它视全部的输入均为字符串。) 在一个 ENUM 字符串中存储数字是不明智的,由于它可能会打乱思惟。
ENUM 值依照列规格说明中的列表顺序进行排序。(换句话说,ENUM 值依照它们的索引号排序。)举例来讲,对于 ENUM('a', 'b') 'a' 排在 'b' 后,可是对于 ENUM('b', 'a') , 'b' 却排在 'a' 以前。空字符串排在非空字符串前,NULL 值排在其它全部的枚举值前。为了防止意想不到的结果,建议依照字母的顺序定义 ENUM 列表。也能够经过使用 GROUP BY CONCAT(col) 来肯定该以字母顺序排序而不是以索引值。
若是但愿获得一个 ENUM 列的全部可能值,能够使用:
SHOW COLUMNS FROM table_name LIKE enum_colum;
SET 与 ENUM 类型的查询修改操做 SET FOREIGN_KEY_CHECKS=0;
-- Table structure for setenum
DROP TABLE IF EXISTS setenum
; CREATE TABLE setenum
( id
int(11) NOT NULL AUTO_INCREMENT, settype
set('we','周','李','孙','钱','赵') DEFAULT NULL, enumtype
enum('ZZZ','南海','长江','黄河') DEFAULT NULL, PRIMARY KEY (id
) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- Records of setenum
INSERT INTO setenum
VALUES ('1', 'we,周,钱', '南海'); INSERT INTO setenum
VALUES ('2', '钱,赵', '黄河'); INSERT INTO setenum
VALUES ('3', 'we,赵', '南海'); INSERT INTO setenum
VALUES ('4', '李,孙,钱', '长江');
set('we','周','李','孙','钱','赵')=111111=63 enum('ZZZ','南海','长江','黄河')=100=4
以下表所示:
SET类型:低位(右) → 高位(左)
we | 周 | 李 | 孙 | 钱 | 赵 |
---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 |
从右到左排:11111=63
we | 周 | 李 | 孙 | 钱 | 赵 |
---|---|---|---|---|---|
1 | 1 | 0 | 0 | 1 | 0 |
从右到左排:010011=19
we | 周 | 李 | 孙 | 钱 | 赵 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 1 |
从右到左排:110000=48
we | 周 | 李 | 孙 | 钱 | 赵 |
---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0 | 1 |
从右到左排:100001=33
we | 周 | 李 | 孙 | 钱 | 赵 |
---|---|---|---|---|---|
0 | 0 | 1 | 1 | 1 | 0 |
从右到左排:011100=28
ENUM类型
ZZZ | 南海 | 长江 | 黄河 |
---|---|---|---|
1 | 2 | 3 | 4 |
ZZZ | 南海 | 长江 | 黄河 |
1 | 2 | 3 | 4 |
黄河=4=100
ZZZ | 南海 | 长江 | 黄河 |
---|---|---|---|
1 | 2 | 3 | 4 |
长江=3=11
ZZZ | 南海 | 长江 | 黄河 |
---|---|---|---|
1 | 2 | 3 | 4 |
南海=2=10
ZZZ | 南海 | 长江 | 黄河 |
---|---|---|---|
1 | 2 | 3 | 4 |
ZZZ=1=1
mysql> select * from setenum; +----+----------+----------+ | id | settype | enumtype | +----+----------+----------+ | 1 | we,周,钱 | 南海 | | 2 | 钱,赵 | 黄河 | | 3 | we,赵 | 南海 | | 4 | 李,孙,钱 | 长江 | +----+----------+----------+ 4 rows in set
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum; +----------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +----------+-----------+----------------+----------+------------+-----------------+ | we,周,钱 | 19 | 10011 | 南海 | 2 | 10 | | 钱,赵 | 48 | 110000 | 黄河 | 4 | 100 | | we,赵 | 33 | 100001 | 南海 | 2 | 10 | | 李,孙,钱 | 28 | 11100 | 长江 | 3 | 11 | +----------+-----------+----------------+----------+------------+-----------------+ 4 rows in set
mysql> select * from setenum where settype=33; +----+---------+----------+ | id | settype | enumtype | +----+---------+----------+ | 3 | we,赵 | 南海 | +----+---------+----------+ 1 row in set
mysql> select * from setenum where enumtype=2; +----+----------+----------+ | id | settype | enumtype | +----+----------+----------+ | 1 | we,周,钱 | 南海 | | 3 | we,赵 | 南海 | +----+----------+----------+ 2 rows in set
--不支持二进制查询 mysql> select * from setenum where settype=b'010011'; Empty set
mysql> select * from setenum where settype=b'10011'; Empty set
mysql> select * from setenum where enumtype=b'100'; Empty set
mysql> SELECT * FROM setenum WHERE settype LIKE '%赵%'; +----+---------+----------+ | id | settype | enumtype | +----+---------+----------+ | 2 | 钱,赵 | 黄河 | | 3 | we,赵 | 南海 | +----+---------+----------+ 2 rows in set
--与FIND_IN_SET函数同 mysql> SELECT * FROM setenum WHERE FIND_IN_SET('赵',settype)>0; +----+---------+----------+ | id | settype | enumtype | +----+---------+----------+ | 2 | 钱,赵 | 黄河 | | 3 | we,赵 | 南海 | +----+---------+----------+ 2 rows in set
--当查询只是集合某个值的一部分时,与FIND_IN_SET函数不一样 mysql> SELECT * FROM setenum WHERE FIND_IN_SET('e',settype)>0; Empty set
mysql> SELECT * FROM setenum WHERE settype LIKE '%e%'; +----+----------+----------+ | id | settype | enumtype | +----+----------+----------+ | 1 | we,周,钱 | 南海 | | 3 | we,赵 | 南海 | +----+----------+----------+ 2 rows in set
mysql> SELECT * FROM setenum WHERE settype LIKE '赵'; Empty set
mysql> SELECT * FROM setenum WHERE settype = '赵'; Empty set
mysql> SELECT * FROM setenum WHERE settype LIKE 'we,赵'; +----+---------+----------+ | id | settype | enumtype | +----+---------+----------+ | 3 | we,赵 | 南海 | +----+---------+----------+ 1 row in set
mysql> SELECT * FROM setenum WHERE settype = 'we,赵'; +----+---------+----------+ | id | settype | enumtype | +----+---------+----------+ | 3 | we,赵 | 南海 | +----+---------+----------+ 1 row in set
--若是把集合的顺序改一下,照样无效 mysql> SELECT * FROM setenum WHERE settype LIKE '赵,we'; Empty set
mysql> SELECT * FROM setenum WHERE settype = '赵,we'; Empty set
mysql> SELECT * FROM setenum WHERE enumtype LIKE '%海%';
+----+----------+----------+ | id | settype | enumtype | +----+----------+----------+ | 1 | we,周,钱 | 南海 | | 3 | we,赵 | 南海 | +----+----------+----------+ 2 rows in set
mysql> SELECT * FROM setenum WHERE enumtype = '南海'; +----+----------+----------+ | id | settype | enumtype | +----+----------+----------+ | 1 | we,周,钱 | 南海 | | 3 | we,赵 | 南海 | +----+----------+----------+ 2 rows in set
mysql> SELECT * FROM setenum WHERE enumtype = '海'; Empty set
--------------------UPDATE 语法--------------------
set('we','周','李','孙','钱','赵')=111111=63
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +----------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +----------+-----------+----------------+----------+------------+-----------------+ | we,周,钱 | 19 | 10011 | 南海 | 2 | 10 | +----------+-----------+----------------+----------+------------+-----------------+ 1 row in set
mysql> update setenum set settype = 2 where id=1; Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +---------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +---------+-----------+----------------+----------+------------+-----------------+ | 周 | 2 | 10 | 南海 | 2 | 10 | +---------+-----------+----------------+----------+------------+-----------------+ 1 row in set
--修改settype让其'we'、'周'、'李' 成员为真 mysql> update setenum set settype =settype|1|4|6 where id=1; Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0
--|1|4|6 表示 二进制的OR运算 1 or 100 or 110 = 111 = 7 --实际与 1|6 结果是同样的:1 or 110 = 111 = 7
we | 周 | 李 | 孙 | 钱 | 赵 |
---|---|---|---|---|---|
1 | 1 | 1 | 0 | 0 | 0 |
从右到左排:000111=7
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +----------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +----------+-----------+----------------+----------+------------+-----------------+ | we,周,李 | 7 | 111 | 南海 | 2 | 10 | +----------+-----------+----------------+----------+------------+-----------------+ 1 row in set
--实际与 1|6 结果是同样的:1 or 110 = 111 = 7 mysql> update setenum set settype =settype|1|6 where id=1; Query OK, 0 rows affected Rows matched: 1 Changed: 0 Warnings: 0
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +----------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +----------+-----------+----------------+----------+------------+-----------------+ | we,周,李 | 7 | 111 | 南海 | 2 | 10 | +----------+-----------+----------------+----------+------------+-----------------+ 1 row in set
--settype|1|6 的settype 能够省略,结果同样 mysql> update setenum set settype = 1|6 where id=1; Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +----------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +----------+-----------+----------------+----------+------------+-----------------+ | we,周,李 | 7 | 111 | 南海 | 2 | 10 | +----------+-----------+----------------+----------+------------+-----------------+ 1 row in set
-- &表示与运算,1 and 110 = 0,注意0与NULL不一样 mysql> update setenum set settype = 1 & 6 where id=1; Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +---------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +---------+-----------+----------------+----------+------------+-----------------+ | | 0 | 0 | 南海 | 2 | 10 | +---------+-----------+----------------+----------+------------+-----------------+ 1 row in set
-- &表示与运算,~表示反运算,6=110,~6=001,1 and 001 = 1 mysql> update setenum set settype = null where id=1; Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +---------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +---------+-----------+----------------+----------+------------+-----------------+ | NULL | NULL | NULL | 南海 | 2 | 10 | +---------+-----------+----------------+----------+------------+-----------------+ 1 row in set
mysql> update setenum set settype = 1 & ~6 where id=1; Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +---------+-----------+----------------+----------+------------+-----------------+ | settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) | +---------+-----------+----------------+----------+------------+-----------------+ | we | 1 | 1 | 南海 | 2 | 10 | +---------+-----------+----------------+----------+------------+-----------------+ 1 row in set
-- 5 and ~1 = 101 and ~1 = 101 and 111110 = 100 = 4 mysql> update setenum set settype = null where id=1; Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0
mysql> update setenum set settype = 5 & ~1 where id=1; Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0
we | 周 | 李 | 孙 | 钱 | 赵 |
---|---|---|---|---|---|
0 | 0 | 1 | 0 | 0 | 0 |
从右到左排:000100=4
mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1; +---------+-----------+----------------+----------+------------+-----------------+
settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
---|---|---|---|---|---|
+---------+-----------+----------------+----------+------------+-----------------+ | |||||
李 | 4 | 100 | 南海 | 2 | 10 |
---- | ---- | ---- | ---- | ---- | ---- |
+---------+-----------+----------------+----------+------------+-----------------+ | |||||
1 row in set |
枚举和集合的简单运用
# 枚举与集合:为某一个字段提供选项的 - 枚举只能单选(1个),集合能够多选(0-n个) # 建表 # enum、set默认值为NULL mysql>: create table tc1 (name varchar(20), sex enum('男', '女', '哇塞'), hobbies set('男', '女', '哇塞')); mysql>: insert into tc1 values('ruakei', '哇塞哇塞', '未知'); # enum、set手动设置默认值 '男' 与 '哇塞' mysql>: create table tc2 (name varchar(20), sex enum('男', '女', '哇塞') default '男', hobbies set('男', '女', '哇塞') default '哇塞'); mysql>: insert into tc2 values('ruakei', '哇塞哇塞', '未知'); mysql>: insert into tc2(name) values('ruakei'); # 对sex、hobbies两个字段赋值错误,系统默认用空字符串填充(非安全模式),安全模式抛异常 # 若是对出sex、hobbies两个字段外的其余字段进行赋值,这两个字段会才有默认值 # 注:对set类型的字段进行赋值,用一个字符串,字符串内部用,将多个选项隔开,且不能添加空格等其余额外字符 mysql>: insert into tc2 values('ruakei_1', '女', '男,女,哇塞');
约束
sql约束:约束用于限制加入表的数据的类型。是一种限制,它经过对表的行或列的数据作出限制,来确保表数据的完整性、惟一性能够在建立表时规定约束(经过 CREATE TABLE 语句),或者在表建立以后也能够(经过 ALTER TABLE 语句)。
数据类型的属性
MySQL关键字 | 含义 |
---|---|
NULL | 数据列可包含NULL值 |
NOT NULL | 数据列不容许包含NULL值 |
DEFAULT | 默认值 |
PRIMARY KEY | 主键 |
AUTO_INCREMENT | 自动递增,适用于整数类型 |
UNSIGNED | 无符号 |
CHARACTER SET name | 指定一个字符集 |
一、not null 约束:强制列不接受 NULL 值,强制字段始终包含值。这意味着,若是不向字段添加值,就没法插入新记录或者更新记录。 例:create table table_name(id int not null,name varchar(255) not null); # 强制id和name不能为空 二、unique 约束:惟一标识数据库表中的每条记录,确保表中的一列数据没有相同的值 UNIQUE 和 PRIMARY KEY 约束均为列或列集合提供了惟一性的保证。 PRIMARY KEY 拥有自动定义的 UNIQUE 约束。 每一个表能够有多个 UNIQUE 约束,可是每一个表只能有一个 PRIMARY KEY 约束 例:create table时在id列建立unique约束 create table table_name(id int not null,name varchar(255) not null, unique (id)); 例2:为多个列定义unique create table table_name(id int not null,name varchar(255) not null, constraint uc_personID unique (id,name)) 例3:表已建立状况下,建立unique约束 alter table table_name add unique(id); 多个:alter table table_name add constraint uc_personid unique(id,name); 例4:撤销unique alter table table_name drop index uc_personid; 三、PRIMARY KEY 约束:PRIMARY KEY 约束惟一标识数据库表中的每条记录。 主键必须包含惟一的值。 主键列不能包含 NULL 值。 每一个表都应该有一个主键,而且每一个表只能有一个主键。 primary key = unique + not null 例:create table时在id列建立PRIMARY KEY约束 create table table_name(id int not null,name varchar(255) not null, PRIMARY KEY(id)); 例2:为多个列定义PRIMARY KEY create table table_name(id int not null,name varchar(255) not null, constraint pk_personID PRIMARY KEY (id,name)) 例3:表已建立状况下,建立PRIMARY KEY约束 alter table table_name add PRIMARY KEY(id); 多个:alter table table_name add constraint pk_personid PRIMARY KEY(id,name); 例4:撤销PRIMARY KEY alter table table_name drop index uc_personid; 四、FOREIGN KEY 约束:一个表中的 FOREIGN KEY 指向另外一个表中的 PRIMARY KEY 外键 外键用来在两个表数据之间创建连接,它能够是一列或多列。一个表能够有一个或多个外键 外键对应得是参照完整性,一个表得外键能够为空值,若不为空值,则每个外键值必须等于另外一个表中主键得某个值。 FOREIGN KEY 约束用于预防破坏表之间链接的动做。 FOREIGN KEY 约束也能防止非法数据插入外键列,由于它必须是它指向的那个表中的值之一。 例:create table时在id列建立 FOREIGN KEY 约束 create table table_name1(id int not null,name varchar(255) not null,Id_P int, PRIMARY KEY(id),FOREIGN KEY (Id_P) REFERENCES table_name2(Id_P)); 例2:为多个列定义 FOREIGN KEY create table table_name1(id int not null,name varchar(255) not null,Id_P int, PRIMARY KEY(id) constraint fk_pertb2 FOREIGN KEY (Id_P) REFERENCES table_name2(Id_P) ) 例3:表已建立状况下,建立 FOREIGN KEY 约束 alter table table_name add ADD FOREIGN KEY (Id_P) REFERENCES table_name1(Id_P); 多个:alter table table_name add constraint pk_personid PRIMARY KEY(id,name); 例4:撤销 FOREIGN KEY alter table table_name drop FOREIGN KEY fk_pertb2; 外键约束 mysql> create table bookcategory( -> category_id int primary key, -> category varchar(20), -> parent_id int); mysql> create table bookinfo( -> book_id int primary key, -> book_category_id int, -> constraint fk_cid foreign key(book_category_id) references bookcategory(category_id)); 五、CHECK 约束:用于限制列中的值的范围 若是对单个列定义 CHECK 约束,那么该列只容许特定的值。 若是对一个表定义 CHECK 约束,那么此约束会在特定的列中对值进行限制。 例:create table时在id列建立 CHECK 约束 create table table_name(id int not null,name varchar(255) not null,CHECK(id>0)); 例2:为多个列定义 CHECK 约束 create table table_name(id int not null,name varchar(255) not null, constraint chk_tbname CHECK(id>0 and name='xxx')); 例3:表已建立状况下,建立 CHECK 约束 alter table table_name ADD constraint chk_tbname CHECK (Id_P>0 AND name='xxx'); 例4:撤销 CHECK alter table table_name drop constraint chk_tbname; 六、DEFAULT 约束:用于向列中插入默认值 若是没有规定其余的值,那么会将默认值添加到全部的新记录。 例:create table时在id列建立 DEFAULT 约束,相似 GETDATE() 这样的函数,DEFAULT 约束也能够用于插入系统值 create table table_name(id int not null,name varchar(255) not null DEFAULT 'lxq',timedate date DEFAULT GETDATE()); 例2:表已建立状况下,建立 DEFAULT 约束 alter table table_name alter name set DEFAULT 'lxq2'; 例3:撤销 DEFAULT alter table table_name ALTER name DROP DEFAULT;
约束条件的简单运用
""" primary key:主键,惟一标识,表都会拥有,不设置为默认找第一个 不空,惟一 字段,未标识则建立隐藏字段 foreign key:外键 unique:惟一性数据, 该条字段的值须要保证惟一,不能重复 auto_increment:自增,只能加给key的int类型字段辅助修饰 not null:不为空 - 针对一些字段,如注册时的用户名,出生人的性别等,这些需求下的字段,只不能设置为Null,必需要对其赋值 null 可为空 default:默认值 - 对有默认值意外的字段进行赋值时,有默认值的字段会被赋默认值 unsigned:无符号 - 存储的数字从0开始 zerofill:0填充 - 存整数时数据长度小于取值范围长度,会在数字左方用0填充 """ mysql>: create table td1 (x int, y int default 0, z int default 100); #清空表,并清空主键自增记录 truncate table 数据库.表名; 注: 1.键是用来说的io提供存取效率 2.联合惟一 create table web ( ip char(16), port int, unique(ip,port) ); 3.联合主键 create table web ( ip char(16), port int, primary key(ip,port) ); # eg:1 # 单列惟一 create table t20 ( id int unique ); # 联合惟一 create table web ( ip char(16), port int, unique(ip,port) ); # 若是联合两个字段,两个字段全相同才相同,不然为不一样 insert into web values ('10.10.10.10', 3306), ('10.10.10.10', 3306); # 注: # 1.表默认都有主键, 且只能拥有一个主键字段(单列主键 | 联合主键) # 2.没有设置主键的表, 数据库系统会自上而下将第一个规定为unique not null字段自动提高为primary key主键 # 3.若是整个表都没有unique not null字段且没有primary key字段, 系统会默认建立一个隐藏字段做为主键 # 4.一般必须手动指定表的主键, 通常用id字段, 且id字段通常类型为int, 由于int类型能够auto_increment # eg:2 create table t21(id int auto_increment); # 自增约束必须添加给key的字段 # eg:3 create table t21(id int primary key auto_increment); # 自增要结合key,不赋值插入,数据会自动自增, 且自增的结果一直被记录保留 # eg:4 # 联合主键 create table t22( ip char(16), port int, primary key(ip,port) ); # 若是联合两个字段,两个字段全相同才相同,不然为不一样 insert into web values ('10.10.10.10', 3306), ('10.10.10.10', 3306);
表中字段的详细操做
create table t2( id int primary key auto_increment, x int, y int ); insert into t2(x, y) values(10, 20), (100, 200), (1000, 2000); ''' 1.修改字段信息 alter table 表名 modify 字段名 类型[(宽度) 约束]; alter table t2 modify x bigint default 0; # 模式不一样, 涉及精度问题 2.修改字段名及信息 alter table 表名 change 旧字段名 新字段名 类型[(宽度) 约束]; alter table t2 change y c char(10) not null; # 模式不一样, 涉及类型转换问题 3.添加字段名 # 末尾添加 alter table 表名 add 字段名 类型[(宽度) 约束], ..., add 字段名 类型[(宽度) 约束]; alter table t2 add age int, add gender enum("male", "female", "wasai") default "wasai"; # t头部添加 alter table 表名 add 字段名 类型[(宽度) 约束] first; # 指定位添加:指定字段后 alter table 表名 add 字段名 类型[(宽度) 约束] after 旧字段名; alter table t2 add y int after x; 4.删除字段名 alter table 表名 drop 字段名; alter table t2 drop y; '''
扩展
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。通常说来,数据库只需知足第三范式(3NF)就好了。下面用画图方式简单介绍下前三范式
三范式
1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非主键字段不能相互依赖;
解释: 1NF:原子性 字段不可再分,不然就不是关系数据库; 2NF:惟一性 一个表只说明一个事物; 3NF:每列都与主键有直接关系,不存在传递依赖;
1NF:无重复的列,每一列都是不可分割的基本数据项,同一 列中不能有多个值,即实体中的某个属性不能有多个值或者不 能有重复的属性。除去同类型的字段,就是无重复的列 说明:第一范式(1NF)是对关系模式的基本要求,不知足第 一范式(1NF)的数据库就不是关系数据库
2NF:属性彻底依赖于主键,第二范式必须先知足第一范式, 要求表中的每一个行必须能够被惟一地区分。一般为表加上一个 列,以存储各个实例的惟一标识PK,非PK的字段须要与整个 PK有直接相关性
3NF:属性不依赖于其它非主属性,知足第三范式必须先知足 第二范式。第三范式要求一个数据库表中不包含已在其它表中 已包含的非主关键字信息,非PK的字段间不能有从属关系
四、BCNF(BC范式)
它构建在第三范式的基础上,若是关系模型R是第一范式,且每一个属性都不传递依赖于R的候选键,那么称R为BCNF的模式。
假设仓库管理关系表(仓库号,存储物品号,管理员号,数量),知足一个管理员只在一个仓库工做;一个仓库能够存储多种物品,则存在以下关系:
(仓库号,存储物品号)——>(管理员号,数量)
(管理员号,存储物品号)——>(仓库号,数量)
因此,(仓库号,存储物品号)和(管理员号,存储物品号)都是仓库管理关系表的候选码,表中惟一非关键字段为数量,它是符合第三范式的。可是,因为存在以下决定关系:
(仓库号)——>(管理员号)
(管理员号)——>(仓库号)
即存在关键字段决定关键字段的状况,所以其不符合BCNF。把仓库管理关系表分解为两个关系表仓库管理表(仓库号,管理员号)和仓库表(仓库号,存储物品号,数量),这样这个数据库表是符合BCNF的,并消除了删除异常、插入异常和更新异常。
五、4NF(第四范式)
设R是一个关系模型,D是R上的多值依赖集合。若是D中存在凡多值依赖X->Y时,X必是R的超键,那么称R是第四范式的模式。
例如,职工表(职工编号,职工孩子姓名,职工选修课程),在这个表中,同一个职工可能会有多个职工孩子姓名,一样,同一个职工也可能会有多个职工选修课程,即这里存在着多值事实,不符合第四范式。若是要符合第四范式,只须要将上表分为两个表,使它们只有一个多值事实,例如职工表一(职工编号,职工孩子姓名),职工表二(职工编号,职工选修课程),两个表都只有一个多值事实,因此符合第四范式。
拓展:各范式的关系图以下所示:
表关系
社会中存储须要能够构建成表的数据, 它们造成的表,每每之间存储某种或某些社会关系,
mysql数据库创建表结构就是社会中产生的各类数据, 分门别类管理
但mysql创建的(代码层次的)表之间, 一样须要处理表与表之间的关系
造成了 一对一|一对多 | 多对多 三种关系
外键
1、基本概念
一、MySQL中“键”和“索引”的定义相同,因此外键和主键同样也是索引的一种。不一样的是MySQL会自动为全部表的主键进行索引,可是外键字段必须由用户进行明确的索引。用于外键关系的字段必须在全部的参照表中进行明确地索引,InnoDB不能自动地建立索引。
二、外键能够是一对一的,一个表的记录只能与另外一个表的一条记录链接,或者是一对多的,一个表的记录与另外一个表的多条记录链接。
三、若是须要更好的性能,而且不须要完整性检查,能够选择使用MyISAM表类型,若是想要在MySQL中根据参照完整性来创建表而且但愿在此基础上保持良好的性能,最好选择表结构为innoDB类型。
四、外键的使用条件
① 两个表必须是InnoDB表,MyISAM表暂时不支持外键
② 外键列必须创建了索引,MySQL 4.1.2之后的版本在创建外键时会自动建立索引,但若是在较早的版本则须要显式创建;
③ 外键关系的两个表的列必须是数据类型类似,也就是能够相互转换类型的列,好比int和tinyint能够,而int和char则不能够;
五、外键的好处:能够使得两张表关联,保证数据的一致性和实现一些级联操做。保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。 使两张表造成关联,外键只能引用外表中的列的值!能够使得两张表关联,保证数据的一致性和实现一些级联操做;
2、使用方法
一、建立外键的语法:
外键的定义语法:
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
REFERENCES tbl_name (index_col_name, ...)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
该语法能够在 CREATE TABLE 和 ALTER TABLE 时使用,若是不指定CONSTRAINT symbol,MYSQL会自动生成一个名字。
ON DELETE、ON UPDATE表示事件触发限制,可设参数:
① RESTRICT(限制外表中的外键改动,默认值)
② CASCADE(跟随外键改动)
③ SET NULL(设空值)
④ SET DEFAULT(设默认值)
⑤ NO ACTION(无动做,默认的)
二、示例
1)建立表1
create table repo_table(
repo_id char(13) not null primary key,
repo_name char(14) not null)
type=innodb;
建立表2
mysql> create table busi_table(
-> busi_id char(13) not null primary key,
-> busi_name char(13) not null,
-> repo_id char(13) not null,
-> foreign key(repo_id) references repo_table(repo_id))
-> type=innodb;
2)插入数据
insert into repo_table values("12","sz"); //success
insert into repo_table values("13","cd"); //success
insert into busi_table values("1003","cd", "13"); //success
insert into busi_table values("1002","sz", "12"); //success
insert into busi_table values("1001","gx", "11"); //failed,提示:
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (smb_man
.busi_table
, CONSTRAINT busi_table_ibfk_1
FOREIGN KEY (repo_id
) REFERENCES repo_table
(repo_id
))
3)增长级联操做
mysql> alter table busi_table
-> add constraint id_check
-> foreign key(repo_id)
-> references repo_table(repo_id)
-> on delete cascade
-> on update cascade;
-----
ENGINE=InnoDB DEFAULT CHARSET=gb2312; //另外一种方法,能够替换type=innodb;
三、相关操做
外键约束(表2)对父表(表1)的含义:
在父表上进行update/delete以更新或删除在子表中有一条或多条对应匹配行的候选键时,父表的行为取决于:在定义子表的外键时指定的on update/on delete子句。
关键字 | 含义 |
---|---|
CASCADE | 删除包含与已删除键值有参照关系的全部记录 |
SET NULL | 修改包含与已删除键值有参照关系的全部记录,使用NULL值替换(只能用于已标记为NOT NULL的字段) |
RESTRICT | 拒绝删除要求,直到使用删除键值的辅助表被手工删除,而且没有参照时(这是默认设置,也是最安全的设置) |
NO ACTION | 啥也不作 |
四、其余
在外键上创建索引:
index repo_id (repo_id),
foreign key(repo_id) references repo_table(repo_id))
外键约束使用最多的两种状况无外乎:
1)父表更新时子表也更新,父表删除时若是子表有匹配的项,删除失败;
2)父表更新时子表也更新,父表删除时子表匹配的项也删除。
前一种状况,在外键定义中,咱们使用ON UPDATE CASCADE ON DELETE RESTRICT;后一种状况,能够使用ON UPDATE CASCADE ON DELETE CASCADE。
InnoDB容许你使用ALTER TABLE在一个已经存在的表上增长一个新的外键:
ALTER TABLE tbl_name ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name, ...) REFERENCES tbl_name (index_col_name,...) [ON DELETE reference_option] [ON UPDATE reference_option]
InnoDB也支持使用ALTER TABLE来删除外键:
ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;
为何说外键能保持数据的一致性、完整性
你想一想,你的图中的第一章表切割成了表1和表2,表2的学号引用了表1的学号字段做为外键,假设不创建外键。仅仅是和表1同样单纯性 地设立一个学号字段。那么和创建外键有什么差异呢?
比方表1中张三的学号为20140900001,那么我在表2中插数据的时候在学号字段插20140900001来记录张三的成绩不也是作到了表 的解耦了吗?
这里存在的问题是。在不设置外键的状况下。表2的学号字段和表1的学号字段是没有关联的。仅仅是你本身以为他们有关系而已。数据库并 不以为它俩有关系。也就是说,你在表2的学号字段插了一个值(比方20140999999),但是这个值在表1中并无,这个时候,数据库仍是允 许你插入的,它并不会对插入的数据作关系检查。然而在设置外键的状况下。你插入表2学号字段的值必须要求在表1的学号字段能找到。 同一时候。假设你要删除表1的某个学号字段。必须保证表2中没有引用该字段值的列,不然就无法删除。
这就是所谓的保持数据的一致性和完整性。你想。如 果表2还引用表1的某个学号,你却把表1中的这个学号删了,表2就不知道这个学号相应的学生是哪一个学生。
数据的一致性还包含数据类型的一致性(这 个见如下就知道了)。
外键的使用规范
- 从表的字段必须与外键类型一样(如上。分数表 stu 的类型必须和学生表 sid 的类型一样,比方都是 int(10) 类型)
- 外键必须是主表的惟一键(如上。学生表 sid 是主键,而主键是惟一的。因此可以做为分数表 stu 的外键)
- 有关联的字段(如上,分数表之因此使用学生表的 sid 是因为二者有关联,分数表记录的是学生的分数,而学生可以用 sid 来惟 一标识)
- 避免使用复合键(也就是说从表可以同一时候引用多个外表的字段做为一个外键,通常不推荐这样的作法)
# 做者(author):id,name,sex,age,mobile, detail_id # 做者详情(author_detail): id,info,address # 一、外键的 字段名 能够自定义(名字随意),一般命名规范(关联表_关联字段) # 二、外键要经过 foreign key 语法创建表与表之间的关联 # 三、foreign key(所在表的外键字段) references 关联表(关联字段) # eg:foreign key(detail_id) references author_detail(id) # 四、级联关系 # 级联更新 on update cascade # 级联删除 on delete cascade # 重点:外键字段自己能够惟一或不惟一,可是外键关联的字段必定惟一
多表关系
一对一关系
一对一关系是最好理解的一种关系,在数据库建表的时候能够将人表的主键放置与身份证表里面,也能够将身份证表的主键放置于人表里面
一对多关系
班级是1端,学生是多端,结合面向对象的思想,1端是父亲,多端是儿子,因此多端具备1端的属性,也就是说多端里面应该放置1端的主键,那么学生表里面应该放置班级表里面的主键
多对多关系
对于多对多关系,须要转换成1对多关系,那么就须要一张中间表来转换,这张中间表里面须要存放学生表里面的主键和课程表里面的主键,此时学生与中间表示1对多关系,课程与中间表是1对多关系,学生与课程是多对多关系
''' 一对一:丈夫-妻子,用户-身份证,做者-做者详情 建表规则: 未存放外键的表被依赖,称之为左表;存放外键的表示依赖表,称之为右表;先操做左边再操做右表 # 一对一:外键在任何一方均可以,此时外键要设置 惟一键 一对多:部门-员工,班级-学生,书-出版社 建表规则: 先创建主表,再创建从表,在从表中设置主表的惟一字段(一般为主键)做为外键,外键必须放在多的一方,此时外键值不惟一 多对多:老师-班级,课程-学生,出版社-做者 建表规则: 必定要建立第三张表(关系表),每个外键值不惟一,看能够多个外键创建联合惟一,必定要建立第三张表(关系表),每个外 键值不惟一,看能够多个外键创建联合惟一 '''
一对一:无级联关系
# 做者详情(author_detail): id,info,address create table author_detail( id int primary key auto_increment, info varchar(256), address varchar(256) ); # 做者表id,name,sex,age,mobile, detail_id create table author( id int primary key auto_increment, name varchar(64) not null, mobile char(11) unique not null, sex enum('男', '女') default '男', age int default 0, detail_id int unique not null, foreign key(detail_id) references author_detail(id) ); # 必须先建立被关联表数据,有关联表外键关联的记录后,关联表才能够建立数据 mysql>: insert into author_detail(info,address) values('Tom_info','Tom_address'); mysql>: insert into author(name,mobile,detail_id) values('Tom','13344556677', 1); mysql>: insert into author_detail(info,address) values('Bob_info','Bob_address'); mysql>: insert into author(name,mobile,detail_id) values('Bob','15666882233', 2); # 修改关联表 author mysql>: insert into author_detail(info,address) values('Tom_info_sup','Tom_address_sup'); mysql>: update author set detail_id=3 where detail_id=2; # 有未被其余数据关联的数据,就能够修改 # 删除关联表 author mysql>: delete from author where detail_id=3; # 直接删除 # 修改被关联表 author_detail mysql>: update author_detail set id=10 where id=1; # 没法修改 # 删除被关联表 author_detail mysql>: delete from author_detail where id=1; # 没法删除 # 没有级联关系下: # 增长:先增长被关联表记录,再增长关联表记录 # 删除:先删除关联表记录,再删除被关联表记录 # 更新:关联与被关联表都没法完成 关联的外键和主键 数据更新 - (若是被关联表记录没有被绑定,能够修改)
一对一:有级联关系
mysql>: drop table author; mysql>: drop table author_detail; # 做者详情(author_detail): id,info,address create table author_detail( id int primary key auto_increment, info varchar(256), address varchar(256) ); # 做者表id,name,sex,age,mobile, detail_id create table author( id int primary key auto_increment, name varchar(64) not null, mobile char(11) unique not null, sex enum('男', '女') default '男', age int default 0, detail_id int unique not null, foreign key(detail_id) references author_detail(id) on update cascade on delete cascade ); # 必须先建立被关联表数据,有关联表外键关联的记录后,关联表才能够建立数据 mysql>: insert into author(name,mobile,detail_id) values('Tom','13344556677', 1); # 错误 mysql>: insert into author_detail(info,address) values('Tom_info','Tom_address'); mysql>: insert into author(name,mobile,detail_id) values('Tom','13344556677', 1); mysql>: insert into author_detail(info,address) values('Bob_info','Bob_address'); mysql>: insert into author(name,mobile,detail_id) values('Bob','15666882233', 2); # 修改关联表 author mysql>: update author set detail_id=3 where detail_id=2; # 失败,3详情不存在 mysql>: update author set detail_id=1 where detail_id=2; # 失败,1详情已被关联 mysql>: insert into author_detail(info,address) values('Tom_info_sup','Tom_address_sup'); mysql>: update author set detail_id=3 where detail_id=2; # 有未被其余数据关联的数据,就能够修改 # 删除关联表 author mysql>: delete from author where detail_id=3; # 直接删除 # 修改被关联表 author_detail mysql>: update author_detail set id=10 where id=1; # 级联修改,同步关系关联表外键 # 删除被关联表 author_detail mysql>: delete from author where detail_id=10; # 能够删除对被关联表无影响 mysql>: insert into author(name,mobile,detail_id) values('Tom','13344556677', 10); mysql>: delete from author_detail where id=10; # 能够删除,将关联表的记录级联删除掉
一对多
# 一对多:外键必须放在多的一方,此时外键值不惟一 # 出版社(publish): id,name,address,phone create table publish( id int primary key auto_increment, name varchar(64), address varchar(256), phone char(20) ); # 书(book):id,name,price,publish_id, author_id create table book( id int primary key auto_increment, name varchar(64) not null, price decimal(5, 2) default 0, publish_id int, # 一对多的外键不能设置惟一 foreign key(publish_id) references publish(id) on update cascade on delete cascade ); # 增:先增长被关联表(publish)的数据,再增长关联表(book)的数据 mysql>: insert into publish(name, address, phone) values ('人民出版社', '北京', '010-110'), ('西交大出版社', '西安', '010-119'), ('老男孩出版社', '上海', '010-120'); mysql>: insert into book(name, price, publish_id) values ('西游记', 6.66, 1), ('东游记', 8.66, 1), ('python从入门到入土', 2.66, 2), ('轮程序员修养之道', 3.66, 3), ('好好活着', 88.88, 3); # 没有被关联的字段,插入依旧错误 mysql>: insert into book(name, price, publish_id) values ('打脸之道', 0.3, 4); # 失败 # 更新:直接更新被关联表的(publish) 主键,关联表(book) 外键 会级联更新 mysql>: update publish set id=10 where id=1; # 更新:直接更新关联表的(book) 外键,修改的值对应被关联表(publish) 主键 若是存在,能够更新成功,反之失败 mysql>: update book set publish_id=2 where id=4; # 成功 mysql>: update book set publish_id=1 where id=4; # 失败 # 删: # 删被关联表,关联表会被级联删除 mysql>: delete from publish where id = 2; # 删关联表,被关联表不会发生变化 mysql>: delete from book where publish_id = 3;
# 假设:书与做者也是 一对多 关系,一个做者能够出版多本书 create table book( id int primary key auto_increment, name varchar(64) not null, price decimal(5, 2) default 0, publish_id int, # 一对多的外键不能设置惟一 foreign key(publish_id) references publish(id) on update cascade on delete cascade # 创建与做者 一对多 的外键关联 author_id int, foreign key(author_id) references author(id) on update cascade on delete cascade );
多对多
# 多对多:必定要建立第三张表(关系表),每个外键值不惟一,看能够多个外键创建联合惟一 mysql>: drop table author; mysql>: drop table author_detail; mysql>: drop table book; mysql>: drop table publish; # 做者(author):id, name, age create table author( id int primary key auto_increment, name varchar(64), age int unsigned default 0 ); # 出版社(publish):id, name, address create table publish( id int primary key auto_increment, name varchar(64), address varchar(256) ); # 做者与出版社关系表:id, author_id, publish_id create table author_publish( id int primary key auto_increment, # 关系表必定有多个外键,关联着多张表 # 关联做者表 author_id int, foreign key(author_id) references author(id) on update cascade on delete cascade, # 关联出版社表 publish_id int, foreign key(publish_id) references publish(id) on update cascade on delete cascade, # 创建两个字段的联合惟一 unique(author_id, publish_id) ); # 注:关系表 关联着 做者 和 出版社 两张表,在表结构上 做者 与 出版社 两表键没有任何关系 # 增:两张被关联表,没有先后关系,但关系表必须在两个表都提供数据后才能进行 关系匹配 mysql>: insert into author(name, age) values('ruakei', 67),('engo', 76),('Lxx', 3); mysql>: insert into publish(name, address) values('老男孩出版社', '上海'),('小女孩出版社', '北京'); # 操做关系表: mysql>: insert into author_publish(author_id, publish_id) values(1,1),(1,2),(2,1),(2,2),(3,1); # 关系表操做:增、删、改,只要两张被关系表有提供对应的操做数据,均可以操做成功,且对两张被关系表没有影响 # 操做两张被关系表: # 增:不会影响关系表 mysql>: insert into publish(name, address) values('西交大出版社', '西安'); # 改:关系表都会级联更新 mysql>: update publish set id=10 where id=1; # 删:关系表都会级联删除 mysql>: delete from author where name='ruakei';
单表查询
""" 增: insert [into] [数据库名.]表名[(字段1[, ..., 字段n])] values (数据1[, ..., 数据n])[, ..., (数据1[, ..., 数据n])]; 删: delete from [数据库名.]表名 [条件]; 改: updata [数据库名.]表名 set 字段1=值1[, ..., 字段n=值n] [条件]; 查: select [distinct] 字段1 [[as] 别名1],...,字段n [[as] 别名n] from [数据库名.]表名 [条件]; """ # 条件:from、where、group by、having、distinct、order by、limit => 层层筛选后的结果 # 注:一条查询语句,能够拥有多种筛选条件,条件的顺序必须按照上方顺序进行逐步筛选,distinct稍有特殊(书写位置),条件的种类能够不全 # 能够缺失,但不能乱序
去重:distinct
mysql>: create table t1( id int, x int, y int ); mysql>: insert into t1 values(1, 1, 1), (2, 1, 2), (3, 2, 2), (4, 2, 2); mysql>: select distinct * from t1; # 所有数据 mysql>: select distinct x, y from t1; # 结果 1,1 1,2 2,2 mysql>: select distinct y from t1; # 结果 1 2 # 总结:distinct对参与查询的全部字段,总体去重(所查的所有字段的值都相同,才认为是重复数据)
数据准备
CREATE TABLE `emp` ( `id` int(0) NOT NULL AUTO_INCREMENT, `name` varchar(10) NOT NULL, `gender` enum('男','女','未知') NULL DEFAULT '未知', `age` int(0) NULL DEFAULT 0, `salary` float NULL DEFAULT 0, `area` varchar(20) NULL DEFAULT '中国', `port` varchar(20) DEFAULT '未知', `dep` varchar(20), PRIMARY KEY (`id`) ); INSERT INTO `emp` VALUES (1, 'yangsir', '男', 42, 10.5, '上海', '浦东', '教职部'), (2, 'engo', '男', 38, 9.4, '山东', '济南', '教学部'), (3, 'jerry', '女', 30, 3.0, '江苏', '张家港', '教学部'), (4, 'tank', '女', 28, 2.4, '广州', '广东', '教学部'), (5, 'jiboy', '男', 28, 2.4, '江苏', '苏州', '教学部'), (6, 'zero', '男', 18, 8.8, '中国', '黄浦', '咨询部'), (7, 'owen', '男', 18, 8.8, '安徽', '宣城', '教学部'), (8, 'jason', '男', 28, 9.8, '安徽', '巢湖', '教学部'), (9, 'ying', '女', 36, 1.2, '安徽', '芜湖', '咨询部'), (10, 'kevin', '男', 36, 5.8, '山东', '济南', '教学部'), (11, 'monkey', '女', 28, 1.2, '山东', '青岛', '教职部'), (12, 'san', '男', 30, 9.0, '上海', '浦东', '咨询部'), (13, 'san1', '男', 30, 6.0, '上海', '浦东', '咨询部'), (14, 'san2', '男', 30, 6.0, '上海', '浦西', '教学部'), (15, 'ruakei', '女', 67, 2.501, '上海', '陆家嘴', '教学部');
经常使用函数
""" 拼接:concat() | concat_ws() 大小写:upper() | lower() 浮点型操做:ceil() | floor() | round() 整型:能够直接运算 """ mysql>: select name,area,port from emp; mysql>: select name as 姓名, concat(area,'-',port) 地址 from emp; # 上海-浦东 mysql>: select name as 姓名, concat_ws('-',area,port,dep) 信息 from emp; # 上海-浦东-教职部 mysql>: select upper(name) 姓名大写,lower(name) 姓名小写 from emp; mysql>: select id,salary,ceil(salary)上薪资,floor(salary)下薪资,round(salary)入薪资 from emp; mysql>: select name 姓名, age 旧年龄, age+1 新年龄 from emp;
条件:where
# 多条件协调操做导入:where 奇数 [group by 部门 having 平均薪资] order by [平均]薪资 limit 1 mysql>: select * from emp where id<5 limit 1; # 正常 mysql>: select * from emp limit 1 where id<5; # 异常,条件乱序 # 判断规则 """ 比较符合:> | < | >= | <= | = | != 区间符合:between 开始 and 结束 | in(自定义容器) 逻辑符合:and | or | not 类似符合:like _|% 正则符合:regexp 正则语法 """ mysql>: select * from emp where salary>5; mysql>: select * from emp where id%2=0; mysql>: select * from emp where salary between 6 and 9; mysql>: select * from emp where id in(1, 3, 7, 20); # _o 某o | __o 某某o | _o% 某o* (*是0~n个任意字符) | %o% *o* mysql>: select * from emp where name like '%o%'; mysql>: select * from emp where name like '_o%'; mysql>: select * from emp where name like '___o%'; # sql只支持部分正则语法 mysql>: select * from emp where name regexp '.*\d'; # 不支持\d表明数字,认为\d就是普通字符串 mysql>: select * from emp where name regexp '.*[0-9]'; # 支持[]语法
分组与筛选:group by | having
where与having
# 表象:在没有分组的状况下,where与having结果相同 # 重点:having能够对 聚合结果 进行筛选 mysql>: select * from emp where salary > 5; mysql>: select * from emp having salary > 5; mysql>: select * from emp where id in (5, 10, 15, 20); mysql>: select * from emp having id in (5, 10, 15, 20);
聚合函数
""" max():最大值 min():最小值 avg():平均值 sum():和 count():记数 group_concat():组内字段拼接,用来查看组内其余字段 """
分组查询 group by
# 修改my.ini配置重启mysql服务 sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION # 在sql_mode没有 ONLY_FULL_GROUP_BY 限制下,能够执行,但结果没有意义 # 有 ONLY_FULL_GROUP_BY 限制,报错 mysql>: select * from emp group by dep; # 分组后,表中数据考虑范围就不是 单条记录,由于每一个分组都包含了多条记录,参照分组字段,对每一个分组中的 多条记录 统一处理 # eg: 按部门分组,每一个部门都有哪些人、最高的薪资、最低的薪资、平均薪资、组里一共有多少人 # 将多条数据统一处理,这种方式就叫 聚合 # 每一个部门都有哪些人、最高的薪资、最低的薪资、平均薪资 都称之为 聚合结果 - 聚合函数操做的结果 # 注:参与分组的字段,也归于 聚合结果 mysql>: select dep 部门, group_concat(name) 成员, max(salary) 最高薪资, min(salary) 最低薪资, avg(salary) 平均薪资, sum(salary) 总薪资, count(gender) 人数 from emp group by dep; # 总结:分组后,查询条件只能为 分组字段 和 聚合函数操做的聚合结果
分组后的having
mysql>: select dep 部门, group_concat(name) 成员, max(salary) 最高薪资, min(salary) 最低薪资, avg(salary) 平均薪资, sum(salary) 总薪资, count(gender) 人数 from emp group by dep; # 最低薪资小于2 mysql>: select dep 部门, group_concat(name) 成员, max(salary) 最高薪资, min(salary) 最低薪资, avg(salary) 平均薪资, sum(salary) 总薪资, count(gender) 人数 from emp group by dep having min(salary)<2; # having能够对 聚合结果 再进行筛选,where不能够
排序
排序规则
# order by 主排序字段 [asc|desc], 次排序字段1 [asc|desc], ...次排序字段n [asc|desc]
未分组状态下
mysql>: select * from emp; # 按年龄升序 mysql>: select * from emp order by age asc; # 按薪资降序 mysql>: select * from emp order by salary desc; # 按薪资降序,若是相同,再按年龄降序 mysql>: select * from emp order by salary desc, age desc; # 按龄降序,若是相同,再按薪资降序 mysql>: select * from emp order by age desc, salary desc;
分组状态下
mysql>: select dep 部门, group_concat(name) 成员, max(salary) 最高薪资, min(salary) 最低薪资, avg(salary) 平均薪资, sum(salary) 总薪资, count(gender) 人数 from emp group by dep; # 最高薪资降序 mysql: select dep 部门, group_concat(name) 成员, max(salary) 最高薪资, min(salary) 最低薪资, avg(salary) 平均薪资, sum(salary) 总薪资, count(gender) 人数 from emp group by dep order by 最高薪资 desc;
限制 limit
# 语法:limit 条数 | limit 偏移量,条数 mysql>: select name, salary from emp where salary<8 order by salary desc limit 1; mysql>: select * from emp limit 5,3; # 先偏移5条知足条件的记录,再查询3条
连表查询
链接
# 链接:将有联系的多张表经过关联(有联系就行,不必定是外键)字段,进行链接,形参一张大表 # 连表查询:在大表的基础上进行查询,就称之为连表查询 # 将表与表创建链接的方式有四种:内链接、左链接、右链接、全链接
一对多数据准备
mysql>: create database db3; mysql>: use db3; mysql>: create table dep( id int primary key auto_increment, name varchar(16), work varchar(16) ); create table emp( id int primary key auto_increment, name varchar(16), salary float, dep_id int ); insert into dep values(1, '市场部', '销售'), (2, '教学部', '授课'), (3, '管理部', '开车'); insert into emp(name, salary, dep_id) values('egon', 3.0, 2),('yanghuhu', 2.0, 2),('sanjiang', 10.0, 1),('owen', 88888.0, 2),('liujie', 8.0, 1),('yingjie', 1.2, 0);
笛卡尔积
# 笛卡尔积: 集合 X{a, b} * Y{o, p, q} => Z{{a, o}, {a, p}, {a, q}, {b, o}, {b, p}, {b, q}} mysql>: select * from emp, dep; # 总结:是两张表 记录的全部排列组合,数据没有利用价值
内链接
# 关键字:inner join on # 语法:from A表 inner join B表 on A表.关联字段=B表.关联字段 mysql>: select emp.id,emp.name,salary,dep.name,work from emp inner join dep on emp.dep_id = dep.id order by emp.id; # 总结:只保留两个表有关联的数据
左链接
# 关键字:left join on # 语法:from 左表 left join 右表 on 左表.关联字段=右表.关联字段 mysql>: select emp.id,emp.name,salary,dep.name,work from emp left join dep on emp.dep_id = dep.id order by emp.id; # 总结:保留左表的所有数据,右表有对应数据直接连表显示,没有对应关系空填充
右链接
# 关键字:right join on # 语法:from A表 right join B表 on A表.关联字段=B表关联字段 mysql>: select emp.id,emp.name,salary,dep.name,work from emp right join dep on emp.dep_id = dep.id order by emp.id; # 总结:保留右表的所有数据,左表有对应数据直接连表显示,没有对应关系空填充
左右能够相互转化
mysql>: select emp.id,emp.name,salary,dep.name,work from emp right join dep on emp.dep_id = dep.id order by emp.id; mysql>: select emp.id,emp.name,salary,dep.name,work from dep left join emp on emp.dep_id = dep.id order by emp.id; # 总结:更换一下左右表的位置,相对应更换左右链接关键字,结果相同
全链接
mysql>: select emp.id,emp.name,salary,dep.name,work from emp left join dep on emp.dep_id = dep.id union select emp.id,emp.name,salary,dep.name,work from emp right join dep on emp.dep_id = dep.id order by id; # 总结:左表右表数据都被保留,彼此有对应关系正常显示,彼此没有对应关系均空填充对方
一对一与一对多状况一致
# 建立一对一 做者与做者详情 表 create table author( id int, name varchar(64), detail_id int ); create table author_detail( id int, phone varchar(11) ); # 填充数据 insert into author values(1, 'Bob', 1), (2, 'Tom', 2), (3, 'ruakei', 0); insert into author_detail values(1, '13344556677'), (2, '14466779988'), (3, '12344332255'); # 内连 select author.id,name,phone from author join author_detail on author.detail_id = author_detail.id order by author.id; # 全连 select author.id,name,phone from author left join author_detail on author.detail_id = author_detail.id union select author.id,name,phone from author right join author_detail on author.detail_id = author_detail.id order by id;
多对多:两表两表创建链接
# 在一对一基础上,创建 做者与书 的多对多关系关系 # 利用以前的做者表 create table author( id int, name varchar(64), detail_id int ); insert into author values(1, 'Bob', 1), (2, 'Tom', 2), (3, 'ruakei', 0); # 建立新的书表 create table book( id int, name varchar(64), price decimal(5,2) ); insert into book values(1, 'python', 3.66), (2, 'Linux', 2.66), (3, 'Go', 4.66); # 建立 做者与书 的关系表 create table author_book( id int, author_id int, book_id int ); # 数据:author-book:1-1,2 2-2,3 3-1,3 insert into author_book values(1,1,1),(2,1,2),(3,2,2),(4,2,3),(5,3,1),(6,3,3); # 将有关联的表一一创建链接,查询因此本身所需字段 select book.name, book.price, author.name, author_detail.phone from book join author_book on book.id = author_book.book_id join author on author_book.author_id = author.id left join author_detail on author.detail_id = author_detail.id;