MySQL笔记
连接查询
内连接:返回两个表交集的记录(A∩B):
语句:
SELECT *
FROM a_table a
INNER JOIN b_table b
ON a.a_id = b.b_id;
上述语句将会返回a_id和b_id相等的记录,也就是a_id和b_id两个字段有交集的记录。
第一步:先确定主表,FROM <表1>
第二步:确定连接的表,INNER JOIN <表2>
第三步:然后确定连接条件,ON <条件…>
第四步:加上 WHERE 、ORDER BY等句子。
左外连接:返回左表都存在的记录(A):
语句:
SELECT *
FROM a_table a
LEFT OUTER JOIN b_table b
ON a.a_id = b.b_id;
上述语句将会返回a_id的所有记录,如果某记录的字段不存在,则显示NULL。
右外连接:返回右表都存在的记录(B):
语句:
SELECT *
FROM a_table a
RIGHT OUTER JOIN b_table b
ON a.a_id = b.b_id;
上述语句将会返回b_id的所有记录,如果某记录的字段不存在,则显示NULL。
全外连接:返回两个表都存在的记录(A∪B):
语句:
SELECT *
FROM a_table a
FULL OUTER JOIN b_table b
ON a.a_id = b.b_id;
上述语句将会返回a_id和b_id的所有记录,如果某记录的字段不存在,则显示NULL。
聚合查询和分组聚合查询
聚合查询
对于统计总数、平均数这类计算,SQL提供了专门的聚合函数,使用聚合函数进行查询,就是聚合查询,它可以快速获得结果。
统计有多少个学生:
SELECT COUNT(id) FROM students;
通常,使用聚合查询时,我们应该给列名设置一个别名,便于处理结果:
SELECT COUNT(id) num FROM students;
除了COUNT()函数外,SQL还提供了如下聚合函数:
函数 | 说明 |
---|---|
SUM | 计算某一列的合计值,该列必须为数值类型 |
AVG | 计算某一列的平均值,该列必须为数值类型 |
MAX | 计算某一列的最大值 |
MIN | 计算某一列的最小值 |
要特别注意:如果聚合查询的WHERE条件没有匹配到任何行,COUNT()会返回0,而SUM()、AVG()、MAX()和MIN()会返回NULL:
分组聚合
GROUP BY
如果我们要统计一班的学生数量,我们知道,可以用SELECT COUNT(*) num FROM students WHERE class_id = 1;。如果要继续统计二班、三班的学生数量,难道必须不断修改WHERE条件来执行SELECT语句吗?
按class_id分组:
SELECT COUNT(*) num FROM students GROUP BY class_id;
SELECT COUNT(*) num,class_id,gender
FROM students
GROUP BY class_id, gender
ORDER BY class_id DESC;
事务
在执行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;
这两条SQL语句必须全部执行,或者,由于某些原因,如果第一条语句成功,第二条语句失败,就必须全部撤销。
这种把多条语句作为一个整体进行操作的功能,被称为数据库事务。
数据库事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。如果事务失败,那么效果就和没有执行这些SQL一样,不会对数据库数据有任何改动。
ACID特性
可见,数据库事务具有ACID这4个特性:
A:Atomic,原子性 | 将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行; |
---|---|
C:Consistent,一致性 | 事务完成后,所有数据的状态都是一致的,即A账户只要减去了100,B账户则必定加上了100; |
I:Isolation,隔离性 | 如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离; |
D:Duration,持久性 | 即事务完成后,对数据库数据的修改被持久化存储。 |
对于单条SQL语句,数据库系统自动将其作为一个事务执行,这种事务被称为 隐式事务。
隔离级别
对于两个并发执行的事务,如果涉及到操作同一条记录的时候,可能会发生问题。因为并发操作会带来数据的不一致性,包括脏读、不可重复读、幻读等。数据库系统提供了隔离级别来让我们有针对性地选择事务的隔离级别,避免数据不一致的问题。
脏读(读到了一个未提交并且回滚了的数据) | 一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚,那么当前事务读到的数据就是脏数据 |
---|---|
不可重复读(重复读取同一个数据,可是结果不一样) | 在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。 |
幻读(原来不存在的,现在存在了) | 事务 A 根据条件查询得到了 N 条数据,但此时事务 B 删除或者增加了 M 条符合事务 A 查询条件的数据,这样当事务 A 再次进行查询的时候真实的数据集已经发生了变化,但是A却查询不出来这种变化,因此产生了幻读。 |
Serializable | 所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。但是,由于事务是串行执行,所以效率会大大下降 |
SQL标准定义了4种隔离级别,分别对应可能出现的数据不一致的情况:
Isolation Level | 脏读(Dirty Read) | 脏读(Dirty Read) | 幻读(Phantom Read) |
---|---|---|---|
Read Uncommitted | Yes | Yes | Yes |
Read Committed | No | Yes | Yes |
Repeatable Read | No | No | Yes |
RSerializable | No | No | No |
MySQL事物控制
BEGIN :开始一个事务
ROLLBACK: 事务回滚
COMMIT :事务确认
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT * FROM students WHERE id = 1;
COMMIT;