SQL学习(持续更新)
0 函数篇
1 关系模型
1.1 主键
小结
主键是关系表中记录的唯一标识。主键的选取非常重要:主键不要带有业务含义,而应该使用BIGINT自增或者GUID类型。主键也不应该允许。
可以使用多个列作为联合主键,但联合主键并不常用。
1.2 外键
在表中,通过的字段,可以把数据与另一张表关联起来,这种列称为。
外键并不是通过列名实现的,而是通过定义外键约束实现的:
-- 设置外键约束
ALTER TABLE students
ADD CONSTRAINT fk_class_id
FOREIGN KEY (class_id)
REFERENCES classes (id);
-- 删除外键约束
ALTER TABLE students
DROP FOREIGN KEY fk_class_id;
多对多关系
多对多关系实际上是通过两个一对多关系实现的,即通过一个中间表,关联两个一对多关系,就形成了多对多关系。
小结
关系数据库通过外键可以实现一对多、多对多和一对一的关系。外键既可以通过数据库来约束,也可以不设置约束,仅依靠应用程序的逻辑来保证。
1.3 索引
索引是关系数据库中对某一列或多个列的值进行预排序的数据结构。通过使用索引,可以让数据库系统不必扫描整个表,而是直接定位到符合条件的记录,这样就大大加快了查询速度。
-- 创建索引
ALTER TABLE students
ADD INDEX idx_score (score);
-- 使用ADD INDEX idx_score (score)就创建了一个名称为idx_score,使用列score的索引。索引名称是任意的,索引如果有多列,可以在括号里依次写上
索引的效率
索引的效率取决于索引列的值是否散列,即该列的值如果越互不相同,那么索引效率越高。
索引的优点是提高了查询效率,缺点是在插入、更新和删除记录时,需要同时修改索引,因此,索引越多,插入、更新和删除记录的速度就越慢。
对于主键,关系数据库会自动对其创建主键索引。使用主键索引的效率是最高的,因为主键会保证绝对唯一。
唯一索引
-- 创建唯一索引
ALTER TABLE students
ADD UNIQUE INDEX uni_name (name);
-- 添加唯一约束不创建唯一索引
ALTER TABLE students
ADD CONSTRAINT uni_name UNIQUE (name);
小结
通过对数据库表创建索引,可以提高查询速度。
通过创建唯一索引,可以保证某一列的值具有唯一性。
数据库索引对于用户和应用程序来说都是透明的。
2 查询数据
2.1 基本查询
小结
使用SELECT查询的基本语句可以查询一个表的所有行和所有列的数据。
SELECT查询的结果是一个二维表。
2.2 条件查询
小结
通过条件查询,可以筛选出符合指定条件的记录,而不是整个表的所有记录。
返回的二维表结构和原表是相同的,即结果集的所有列与原表的所有列都一一对应。
2.3 投影查询
用,让结果集仅包含指定列。这种操作称为投影查询。
小结
使用表示查询表的所有列,使用则可以仅返回指定列,这种操作称为投影。
语句可以对结果集的列进行重命名。
2.4 排序 ORDER BY
如果列有相同的数据,要进一步排序,可以继续添加列名。
SELECT id, name, gender, score FROM students ORDER BY score, gender;
默认的排序规则是:“升序”,即从小到大。可以省略,即和效果一样。“倒序”DESC
如果有子句,那么子句要放到子句后面。
2.5 分页查询
分页实际上就是从结果集中“截取”出第M~N条记录。这个查询可以通过子句实现。
-- 结果集分页,每页3条记录。要获取第1页的记录,可以使用LIMIT 3 OFFSET 0
SELECT id, name, gender, score
FROM students
ORDER BY score DESC
LIMIT 3 OFFSET 0;
分页查询的关键在于,首先要确定每页需要显示的结果数量(这里是3),然后根据当前页的索引(从1开始),确定和应该设定的值:
总是设定为;
计算公式为。
这样就能正确查询出第N页的记录集。
注:超过了查询的最大数量并不会报错,而是得到一个空的结果集。
小结
使用可以对结果集进行分页,每次查询返回结果集的一部分;
分页查询需要先确定每页的数量和当前页数,然后确定和的值。
使用分页时,随着越来越大,查询效率也会越来越低。
是可选的,如果只写,那么相当于。
在MySQL中,还可以简写成。
2.6 聚合查询
和函数并不限于数值类型。如果是字符类型,和会返回排序最后和排序最前的字符。
如果聚合查询的条件没有匹配到任何行,会返回0,而、、和会返回
分组 GROUP BY
2.7 多表查询
小结
使用多表查询可以获取M x N行记录;
多表查询的结果集可能非常巨大,要小心使用。
2.8 连接查询
注意INNER JOIN查询的写法是:
小结
JOIN查询需要先确定主表,然后把另一个表的数据“附加”到结果集上;
INNER JOIN是最常用的一种JOIN查询,它的语法是;
JOIN查询仍然可以使用条件和排序。
3 修改数据
3.1 INSERT
-- instert语法
INSERT INTO <表名> (字段1, 字段2, ...) VALUES (值1, 值2, ...);
-- example
INSERT INTO students (class_id, name, gender, score) VALUES
(1, '大宝', 'M', 87),
(2, '二宝', 'M', 81);
小结
使用,我们就可以一次向一个表中插入一条或多条记录。
3.2 UPDATE
我们想更新表的记录的和这两个字段,先写出,然后在子句中写出需要更新的行的筛选条件
UPDATE students SET name='大牛', score=66 WHERE id=1;
小结
使用,我们就可以一次更新表中的一条或多条记录。
3.3 DELETE
小结
使用,我们就可以一次删除表中的一条或多条记录。
4 MYSQL
4.1 管理mysql
4.2 实用SQL语句
5 事务
在执行SQL语句的时候,某些业务要求,一系列操作必须全部执行,而不能仅执行一部分。
-- 从id=1的账户给id=2的账户转账100元
-- 第一步:将id=1的A账户余额减去100
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 第二步:将id=2的B账户余额加上100
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
数据库事务具有ACID这4个特性:
A:Atomic,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
C:Consistent,一致性,事务完成后,所有数据的状态都是一致的,即A账户只要减去了100,B账户则必定加上了100;
I:Isolation,隔离性,如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离;
D:Duration,持久性,即事务完成后,对数据库数据的修改被持久化存储。
对于单条SQL语句,数据库系统自动将其作为一个事务执行,这种事务被称为
要手动把多条SQL语句作为一个事务执行,使用开启一个事务,使用提交一个事务,这种事务被称为
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
有些时候,我们希望主动让事务失败,这时,可以用回滚事务,整个事务会失败
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
ROLLBACK;
SQL标准定义了4种隔离级别,分别对应可能出现的数据不一致的情况
数据库事务具有ACID特性,用来保证多条SQL的全部执行。
5.1 Read Unconnitted
Read Uncommitted是隔离级别最低的一种事务级别。在这种隔离级别下,一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚,那么当前事务读到的数据就是脏数据,这就是脏读(Dirty Read)。
当事务A执行完第3步时,它更新了的记录,但并未提交,而事务B在第4步读取到的数据就是未提交的数据。
随后,事务A在第5步进行了回滚,事务B再次读取的记录,发现和上一次读取到的数据不一致,这就是脏读。
5.2 Read Committed
在Read Committed隔离级别下,一个事务可能会遇到不可重复读(Non Repeatable Read)的问题。
当事务B第一次执行第3步的查询时,得到的结果是,随后,由于事务A在第4步更新了这条记录并提交,所以,事务B在第6步再次执行同样的查询时,得到的结果就变成了,因此,在Read Committed隔离级别下,事务不可重复读同一条记录,因为很可能读到的结果不一致。
5.3 Repeatable Read
在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。
幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。
事务B在第3步第一次读取的记录时,读到的记录为空,说明不存在的记录。随后,事务A在第4步插入了一条的记录并提交。事务B在第6步再次读取的记录时,读到的记录仍然为空,但是,事务B在第7步试图更新这条不存在的记录时,竟然成功了,并且,事务B在第8步再次读取的记录时,记录出现了。
可见,幻读就是没有读到的记录,以为不存在,但其实是可以更新成功的,并且,更新成功后,再次读取,就出现了。
5.4 Serializable
Serializable是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。
虽然Serializable隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用Serializable隔离级别。
默认隔离级别
如果没有指定隔离级别,数据库就会使用默认的隔离级别。在MySQL中,如果使用InnoDB,默认的隔离级别是Repeatable Read。