参考:廖雪峰 SQL教程(MySQL)
- 说明
○ SQL是访问和处理关系数据库的计算机标准语言。无论什么语言,只要涉及操作数据库,都需要通过SQL完成
○ NoSQL:非SQL数据库,包括MongoDB、Cassandra、Dynamo等,都不是关系数据库。
○ 数据库的必要性:我们很多时候需要保存数据,可以有很多种方式保存数据,如Word、Excel这些办公软件,但这些是给我们自己看的,如果要让计算机自己读取,比如保存一个班级的所有学生信息,也容易做到,如C语言可以定义一个结构然后用fwrite写,fread读,其他软件可以将数据保存为json格式或者CSV文件,但对于数据量很大的情况,有时光是读写就需要花很大功夫,还可能需要从数据中查找某些特定的数据。应用程序自身的读取系统还是存在局限性的,一方面效率低,一方面每个程序访问数据的接口不同,使得读取数据的操作变得繁琐。这时,专门用于管理数据的工具--数据库就出现了,管理和读写数据通过数据库提供的接口来完成,应用程序不需要关心数据怎么存储。
○ 数据库按照数据结构来组织、存储和管理数据,数据库一共有三种模型:
§ 层次模型:以“上下级”的层次关系来组织数据的一种方式,看起来像一棵树
§ 网状模型:把每个数据节点和其他很多节点连接起来,看起来像城市之间的路网
§ 关系模型:把数据看作是一个二维表格,任何数据可以通过行号+列号确定
○ 最终关系模型的关系数据库获得了绝对的市场份额,因为关系模型理解和使用起来最简单
○ 数据类型:
§ INT
§ BIGINT
§ REAL
§ DOUBLE
§ DECIMAL(M,N)
§ CHAR(N)
§ VARCHAR(N)
§ BOOLEAN
§ DATE
§ TIME
§ DATETIME
○ 主流关系数据库
§ 商用数据库:Oracle,SQL Server,DB2等
§ 开源数据库:MySQL,PostgreSQL等
§ 桌面数据库:以Access为代表
§ 嵌入式数据库:以Sqlite为代表
○ SQL:结构化查询语言,可查询、更新、添加、删除数据库中的数据,也可以对数据库进行管理和维护,不同数据库都支持SQL。SQL已被ANSI组织定为标准,但不同的数据库对标准的SQL支持不一致。大部分数据库在标准的SQL上做了扩展。~方言
○ 有几种操作数据库的能力:
§ DDL: Data Definition Language:创建表、删除表,修改表结构这些操作
§ DML: Data Manipulation Language:添加、删除、更新数据的能力
§ DQL: Data Query Language:查询数据
○ SQL关键字不区分大小写,但对于表名和列名有的区分有的不区分
- 安装MySQL
○ MySQL是使用最广泛的开源关系数据库。最早是瑞典的一家公司,后被SUN收购,然后SUN又被Oracle收购,所以MySQL最终成为了Oracle旗下的产品
○ MySQL本身只是一个SQL接口,内部包含多种数据引擎,如:
§ InnoDB
§ MyISAM
○ MySQL的衍生版本:
§ MariaDB
§ Aurora
§ PolarDB
○ MySQL官方又分了好几个版本:
§ Community Edition
§ Standard Edition
§ Enterprise Edition
§ Cluster Carrier Grade Edition
○ 安装:
§ 通过官网下载安装,然后添加路径到环境变量就行了
§ 在命令行下输入:mysql -u root -p,然后输入密码就行了
- 关系模型
○ 关系模型本质上是若干个存储数据的二维表。
○ 表的每一行称为记录,Record,记录一个逻辑意义上的数据
○ 表的每一列称为字段,Column,同一表的每一行记录都拥有相同的若干字段。
○ 字段定义了数据类型,以及是否允许为NULL。NULL表示字段数据不存在。
○ 和Excel表不同的是,关系数据库的表和表之间需要建立一对多,多对一和一对一的关系,这样才能够按照应用程序的逻辑来组织和存储数据。
○ 主键
§ 关系数据中,一张表中的一行数据称为一条记录,由多个字段组成。
§ 一条记录包含定义好的若干字段,同一个表中的 所有记录都有相同的字段定义。
§ 关系表中一个重要的约束:任意两条记录不能重复,区分两条记录的唯一字段称为主键。
§ 对主键的要求:记录一旦插入表中最好不要修改主键,修改主键会造成一系列影响。
§ 主键的选取十分重要,一个基本原则是:不使用任何业务相关的字段作为主键。
§ 身份证号、手机号、邮箱地址这些看上去可以作为唯一字段,都不能作为主键。
§ 主键最好是业务无关的字段,可以命名为id,常见的可作为id字段的类型有:
□ 自增整数类型,插入数据时为每一条记录分配一个自增整数。
□ 全局唯一GUID类型:用一种全局唯一的字符串作为主键。通过GUID算法,通过网卡MAC地址、时间戳和随机数生成。
§ 通常自增类型的主键就能满足需求。BIGINT NOT NULL AUTO_INCREMENT
§ 关系数据库还允许通过多个字段唯一表示记录,即两个或多个字段都设置为主键,称为联合主键。
§ 联合主键允许有一列有重复。
○ 外键
§ 两个表:students表和classes表,这两个表是多对一的,为了表达这样的关系,我们需要在students表中加入一列class_id,让它的值与classes表中某条记录相对应。这种列称为外键。
§ 它是通过定义外键约束来实现的:
□ ALTER TABLE students
□ ADD CONSTRAINT fk_class_id
□ FOREIGN KEY (class_id)
□ REFERENCES classes (id);
§ 通过外键约束,关系数据库可以保证无法插入无效的数据。即插入students表中的记录中的class_id值要能和classes表中的id值对应。
§ 由于外键约束会降低数据库的性能,大多数互联网应用程序不会设置外键,仅靠程序自身来保证逻辑的正确性。
§ 删除一个外键约束也是通过 ALTER TABLE实现:
□ ALTER TABLE students
□ DROP FOREIGN KEY fk_class_id;
§ 多对多关系是通过两个一对多关系实现的,即通过一个中间表,关联两个一对多关系。
§ 一对一
○ 索引
§ 索引是关系数据库中对某一列或多个列的值进行预排序的数据结构。通过使用索引,直接定位到符合条件的记录上,这样可以大大加快查询速度。
□ Alter TABLE students
□ ADD INDEX idx_score (score);
§ 索引的效率取决于索引列的值是否散列,该列的值越互不相同效率越高。
§ 唯一索引
□ 设计关系数据表时,有些列,如身份证、邮箱地址等,不适合作为主键(有可能需要修改数据),但根据业务要求,具有唯一性约束,这时可以给该列添加一个唯一索引。如,我们可以假设students表的name不能重复:
® ALTER TABLE students
® ADD UNIQUE INDEX uni_name(name);
□ 通过关键字UNIQUE我们添加了一个唯一索引。也可以只添加唯一约束而不创建唯一索引:
® ALTER TABLE students
® ADD CONSTRAINT uni_name UNIQUE (name);
- 查询数据
○ 一些指令:
§ show databases;//展示数据库列表
§ create databases if not exists name;//name 为数据库名,创建一个名为name的数据库
§ drop databases name;//删除数据库
§ create tabble class(id int not null auto_increment primary key,char name(10) not null);//创建表
§ drop table class;//删除表
§ select * from class;//显示整个表
§ desc class;//显示表的内部结构
○ 基本查询
§ 条件查询
□ where 条件来设定查询条件:select * from students where score >=80;
□ 条件表达式中可以加 and、or、not,逻辑运算。
□ select * from students where score >=80 and score<90;
□ select * from students where score >=80 or score <70;
□ select * from students where not score=90;//判断相等用一个等号就行了
□ select * from students where score<>90;//<>表示不相等
§ 投影查询
□ select name,score from students;//只显示指定列的值
§ 排序
□ select id,name,gender,score from students order by score;//默认升序排列,asc可省略
□ select id,name,gender,score from students order by score desc;//desc使它按降序排列
□ select id,name,gender,score from students order by score desc,gender;//表示先按score降序排列,如果有相同的在按gender排列。
□ select id,name,gender,score from students where score>80 order by score desc,gender;
§ 分页查询
□ select *from students order by score desc limit 3 offset 0;//limit 3 offset 0:从第0项开始显示3项
□ select *from students order by score desc limit 3 offset 3;//相当于第二页
□ offset 0可以省略,limit 3 offset 3=>limit 3,3: select *from students order by score desc limit 3,3;
§ 聚合查询
□ select count(*) from students;//count(*)可以统计查询的结果的行数
□ select count(id) from students;
□ select count(*)id from students;
□ select count(id) from students where gender='M';//统计男生的数量
□ 另外还有
® sum :计算某一列的和,该列必须是数值类型:select sum(score) from students;
® avg:平均值,数值类型
® max
® min
□ 分组,group by:select count(*) from students group by class_id;//查询每一班的人数
□ select avg(score) from students group by class_id;//统计每一班的平均成绩
§ 多表查询
□ select * from students,class;//结果为两个表的乘积
□ select students.id sid,students.name,students.gender,students.score,class.id cid,class.name cname from students,class;//可以给列取别名以免两个表的列名相同不好分辨
□ select s.id sid,s.name,s.gender,s.score,c.id cid,c.name cname from students s,class c;//同时还可以给表取别名
§ 连接查询
□ select s.id, s.name,s.class_id,c.name class_name,s.gender,s.score from students s inner join class c on s.class_id=c.id;
□ select s.id, s.name,s.class_id,c.name class_name,s.gender,s.score from students s right outer join class c on s.class_id=c.id;
□ inner join,内连接,left outer join 返回左表都存在的行,right outer join返回右表都存在的行,full outer join 返回两表都存在的行
- 修改数据
○ insert into students(class_id,name,gender,score)values (1,'da bao','M',87);
○ update: update students set name='da niu',score=66 where id=1;//注意不加where语句的话整个表的所有行的数据都会被修改。
○ delete: delete from students where id=1;
- MySQL
○ 安装完成MySQL后,有MySQL Server和MySQL Client,即MySQL服务器和命令行客户端,可通过MySQL Client登录MySQL。
○ MySQL Client的可执行程序是mysql,MySQL Server的可执行程序是mysqld。
○ MySQL Client中输入的语句通过TCP连接发送到MySQL Server,默认端口号为3306,即如果发送到本机MySQL Server,地址是127.0.0.1::3306
○ 也可以只安装MySQL Client,然后连接到远程MySQL Server,用-h指定ip或者域名:mysql -h 10.0.1.99 -u root -p
○ 管理MySQL
§ 可以使用可视化图形界面MySQL WorkBench,它本质上还是发送SQL语句并执行。
§ 通过命令管理:
□ show databases;//会列出所有的数据库,其中information_schema、mysql、performance_schema和sys是系统库
□ show create table students;//查看创建表的SQL语句
□ alter table students add column birth varchar(10) not null;//给表新增一列
□ alter table students drop column birth;//删除表中的某一列
□ exit;//退出
○ 一些实用的SQL语句
§ 插入或替换,replace语句插入一条记录,如果记录已存在就删除原记录再插入。用法同insert.
§ replace into students(id,class_id,name,gender,score) values(2,2,'xiao ming','F',99);
§ 插入或更新:插入一条记录,如果记录存在则更新该记录:
§ insert into students(id,class_id,name,gender,score) values(1,1,'xiao hong','F',88) on duplicate key update name='xiao hong',gender='F';
§ 插入或忽略:插入一条记录,如果存在则忽略
§ insert ignore into students (id,class_id,name,gender,score) values(1,1,'xiao hong','F',99);
§ 对一个表进行快照,即复制一份当前的表的数据到一个新表
§ create table students_copy select *from students where score>70;
§ 写入查询结果集
§ create table statics(id int not null auto_increment,class_id int not null,average double not null,primary key(id));
§ insert into statics (class_id,average) select class_id,avg(score) from students group by class_id;
§ 强制使用索引,force index,有时可以提高查询速度
§ select *from students force index (idx_class_id) where class_id=1 order by id desc;
- 事务
○ 执行SQL语句时,有时由于业务要求,一系列操作需要全部执行而不能只执行一部分,如一个转账操作,第一步将id为1的用户的余额扣100,第二步将id为2的用户余额加100,如果第一步成功执行,而第二部失败了,就必须全部撤销。
○ 把多条语句作为整体进心操作的功能称为数据库事务。其中的所有操作要么全部成功要么全部失败。所以事务具有ACID四个特性:
§ A:Atomic,原子性,所有的SQL作为原子工作单元执行
§ C:Consisitent,一致性,事务完成后所有的数据的状态都是一致的
§ I:Isolation,隔离性,多个事务并发执行,每个事务做出的修改必须与其他事务隔离
§ D:Duration,持久性,事务完成后,对数据库数据的修改被持久化存储
○ 对单条的SQL语句,数据库系统自动将其作为一个事务执行,这种事务称为隐式事务
○ 多条SQL语句作为事务执行时,使用BEGIN开启要给事务,用COMMIT提交一个事务,这种事务称为显示事务,如:
§ begin;
§ update students set score =score -10 where id=2;
§ update students set score=score +10 where id=1;
§ commit;
○ 也可以不用commit,用rollback回滚事务,导致整个事务失败。
○ 对于两个并发执行的事务,涉及到操作同一条记录时就可能会出现问题。并发操作会带来数据的不一致性,包括脏读、不可重复性、幻读等。SQL定义了4种隔离级别,分别对应可能出现的数据的不一致的情况:
§ Read Uncommitted:隔离级别最低的一种事务,此时一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚,那么当前事务读到的数据就是脏数据,就是脏读。
§ Read Committed:此时一个事务可能会遇到不可重复读的问题:一个事务中多次读取一个数据,如果另一个事务正好修改了这个数据,那么第一个事务中两次读取的数据可能时不一致的。
§ Repeatable Read:一个事务可能会遇到幻读的问题:一个事务中,第一次查询某条记录发现没有,但在试图更新这条不存在的记录时又成功了,再读取同一条记录时它是存在的。
§ Serializable:最严格的隔离级别,此时事务按照次序依次执行,脏读、不可重复读、幻读都不会出现。由于事务是串行执行的,这样的效率会大大下降,应用程序的性能极具降低,所以通常没有必要的化不会使用Serializable隔离级别。
§ 默认隔离级别是Repeatable Read。