大部分內容總結於 《廖雪峯 SQL 筆記》
主鍵
選取主鍵的一個基本原則是:不使用任何業務相關的字段(id)作爲主鍵。修改了主鍵,會造成一系列的影響
類型:
- 自增整數類型(id):
BIGINT NOT NULL AUTO_INCREMENT
。 - 全局唯一 GUID 類型
注意:如果使用 INT 自增類型,那麼當一張表的記錄數超過 2147483647(約21億)時,會達到上限而出錯。使用 BIGINT自增類型則可以最多約 922 億億條記錄。
索引
主鍵默認含有索引。
即該列的值如果越互不相同,那麼索引效率越高。
ALTER TABLE students
ADD INDEX idx_score (score);
多個索引
ALTER TABLE students
ADD INDEX idx_name_score (name, score);
唯一索引保證唯一約束,又是索引,如身份證號、郵箱等字段
ALTER TABLE students
ADD UNIQUE INDEX uni_email (email)
只建唯一約束,不建索引
ALTER TABLE students
ADD CONSTRAINT uni_email UNIQUE (email)
查詢數據
條件查詢
SELECT * FROM <表名> WHERE <條件表達式> (AND / OR)
條件 | 表達式舉例1 | 表達式舉例2 | 說明 |
---|---|---|---|
使用 <> 判斷不相等 | score <> 80 | name <> 'abc' | 常用 <> 代替 Not |
使用 LIKE 判斷相似 | name LIKE 'ab%' | name LIKE '%bc%' | %表示任意字符,例如'ab%'將匹配'ab','abc','abcd' |
投影查詢
SELECT id, score points, name FROM students; // points 爲別名
排序
SELECT id, name, gender, score FROM students ORDER BY score DESC, gender; // 表示先按 score 列倒序,如果有相同分數的,再按 gender 列排序。
- ORDER BY 默認正序,從小到大,DESC descend 倒序
分頁查詢
SELECT id, name, gender, score
FROM students
ORDER BY score DESC
LIMIT 3 OFFSET 0; // 第 1 頁,每頁 3 條
LIMIT 3 OFFSET 3; // 第 2 頁,每頁 3 條
LIMIT <M> OFFSET <N>
顯示從 N+1 行開始,後 M 條記錄。
聚合查詢
SELECT COUNT(*) boys FROM students WHERE gender = 'M';
- COUNT(*)、COUNT(id)、可用 WHERE 條件
- 其他函數:SUM、AVG、MAX、MIN
- 如果是字符類型,MAX() 和 MIN() 會返回排序最後和排序最前的字符
- 結合 GROUP BY 分組:
SELECT class_id, COUNT(*) num FROM students GROUP BY class_id;
- 多個列分組:
SELECT class_id, gender, COUNT(*) num FROM students GROUP BY class_id, gender;
多表查詢
SELECT * FROM students, classes; // 同時查詢 students 表和 classes 表的“乘積”
連接查詢
- 先確定一個主表作爲結果集,然後,把其他表的行有選擇性地「連接」在主表結果集上。
SELECT s.id, s.name, s.class_id, c.name class_name, s.gender, s.score
FROM students s
INNER JOIN classes c
ON s.class_id = c.id;
- 內連接:只查詢符合兩個表的結果,取交集
- 右外連接 RIGHT OUTER JOIN:查詢符合右邊表所有結果,空餘用 NULL 填充
- 左外連接 LEFT OUTER JOIN:查詢符合主表所有結果,空餘用 NULL 填充
- FULL OUTER JOIN,並集
修改數據
INSERT
INSERT INTO <表名> (字段1, 字段2, ...) VALUES (值1, 值2, ...);
INSERT INTO students (class_id, name, gender, score) VALUES
(1, '大寶', 'M', 87),
(2, '二寶', 'M', 81);
UPDATE
UPDATE <表名> SET 字段1=值1, 字段2=值2, ... WHERE ...;
- WHERE 跟 SELECT 的 WHERE 一樣使用
UPDATE students SET score=60;
修改表的所有數據,先用 SELECT 語句測試
DELETE
DELETE FROM <表名> WHERE ...;
DELETE FROM students;
刪除表所有數據
庫/表/列 SQL
也可以只安裝 MySQL Client,然後連接到遠程 MySQL Server。假設遠程 MySQL Server 的 IP 地址是 10.0.1.99,那麼就使用 -h 指定 IP 或域名:
mysql -h 10.0.1.99 -u root -p
庫
SHOW DATABASES;
CREATE DATABASE test;
use test;
DROP DATABASE test;
表
SHOW TABLES;
CREATE TABLE `students` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT "ID",
`class_id` bigint(20) NOT NULL COMMENT "班級 ID",
`name` varchar(100) NOT NULL COMMENT "姓名",
`gender` varchar(1) NOT NULL COMMENT "性別",
`score` int(11) NOT NULL COMMENT "分數",
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT "學生表";
DESC students; // describe,查看錶結構
SHOW CREATE TABLE students; // 查看創建表的語句
DROP TABLE students; // 刪除表
- bigint(20) 後面的 20 指的是字段的長度。最長不超過 20 位(922億億)
- NOT NULL:插入數據時,必須有值
- CHARSET( character set )
- ENGINE=InnoDB DEFAULT:默認引擎 InnoDB
列
ALTER TABLE students ADD COLUMN birth VARCHAR(10) NOT NULL; // 給 students 表新增一列 birth
ALTER TABLE students CHANGE COLUMN birth birthday VARCHAR(20) NOT NULL; // 把列名改爲 birthday,類型改爲 VARCHAR(20)
ALTER TABLE studens DROP COLUMN birthday; // 刪除 birthday 列
EXIT // 退出
實用 SQL
插入或替換
REPLACE INTO students (id, class_id, name, gender, score) VALUES (1, 1, '小明', 'F', 99);
插入或更新
INSERT INTO students (id, class_id, name, gender, score) VALUES (1, 1, '小明', 'F', 99) ON DUPLICATE KEY UPDATE name='小明', gender='F', score=99;
插入或忽略:存在就忽略
INSERT IGNORE INTO students (id, class_id, name, gender, score) VALUES (1, 1, '小明', 'F', 99);
快照:複製當前表的數據到一個新表
-- 對 class_id=1 的記錄進行快照,並存儲爲新表 students_of_class1:
CREATE TABLE students_of_class1 SELECT * FROM students WHERE class_id=1;
寫入查詢結果集
INSERT INTO statistics (class_id, average) SELECT class_id, AVG(score) FROM students GROUP BY class_id;
處理數據表被鎖
show open tables where in_use>0; // 查看錶是否被鎖
show processlist // 查看所有進程
kill id // 殺進程
用戶
SELECT DISTINCT concat('User:''',USER,'''@''',HOST,''';') AS QUERY FROM mysql. USER; // 查看數據庫的所有用戶
show grants for 'label'@'%' // 查看用戶所有表的權限
CREATE USER 'label'@'%' IDENTIFIED BY 'label123'; // 創建用戶
CREATE USER 'label'@'localhost' IDENTIFIED BY 'label123'; // 創建用戶
事務
這種把多條語句作爲一個整體進行操作的功能,被稱爲數據庫 「事務」。
對於單條SQL語句,數據庫系統自動將其作爲一個事務執行,這種事務被稱爲隱式事務。
使用BEGIN
開啓一個事務,使用COMMIT
提交一個事務,這種事務被稱爲 顯式事務
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; // 如果 COMMIT 語句執行失敗了,整個事務也會失敗。
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
ROLLBACK; // 回滾前面執行的 sql
事務有四大特性:原子性:不可分割,要麼成功,要麼失敗;一致性:事務完成後,所有數據的狀態是一致的。隔離性:併發執行的事務,對數據的操作要具有隔離性;持久性:事務完成後,數據就持久化到數據庫中
事務有隔離性有級別,共 4 種,隔離級別由低到高
Isolation Level | 髒讀(Dirty Read) | 不可重複讀(Non Repeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
Read Uncommitted | Yes | Yes | Yes |
Read Committed | - | Yes | Yes |
Repeatable Read | - | - | Yes |
Serializable | - | - | - |
mysql> select * from students;
+----+-------+
| id | name |
+----+-------+
| 1 | Alice |
+----+-------+
1 row in set (0.00 sec)
Read Uncommitted(可讀到未提交)
一個事務可以讀到另一個事務更新,但未提交的數據。如果另一個事務回滾,當前讀取的值就是髒數據,稱爲髒讀。
時刻 | 事務 A | 事務 B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
2 | BEGIN; | BEGIN; |
3 | UPDATE students SET name = 'Bob' WHERE id = 1; | |
4 | SELECT * FROM students WHERE id = 1; // 'Bob' | |
5 | ROLLBACK; | |
6 | SELECT * FROM students WHERE id = 1; // 'Alice' | |
7 | COMMIT; |
Read Commited(可讀到已提交)
存在不可重複讀的問題,事務重複讀時,可能數據不一致。
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 1; // 'Alice' | |
4 | UPDATE students SET name = 'Bob' WHERE id = 1; | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 1; // 'Bob' | |
7 | COMMIT; |
- 第一種情況:兩次讀取都是 Alice
Repeatable Commited(可重複讀)
存在幻讀的問題,幻讀就是沒有讀取的記錄,以爲不存在,但可以更新成功,再次讀取時,就出現了。
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 99; // Empty | |
4 | INSERT INTO students (id, name) VALUES (99, 'Bob'); | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 99; // Empty | |
7 | UPDATE students SET name = 'Alice' WHERE id = 99; | |
8 | SELECT * FROM students WHERE id = 99; // Alice | |
9 | COMMIT; |
其實幻讀影響不大,沒有髒讀和不可重複讀的問題,Mysql 默認隔離級別就是 Repeatable Commited。
- 第一種情況:兩次讀取都是 Alice
- 第二種情況:兩次讀取都是 Alice
Serializable
串行操作,沒有併發。
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL Serializable; | SET TRANSACTION ISOLATION LEVEL Serializable; |
上面三種情況均會報錯。
數據庫語句順序
- 寫的順序:select ... from... where.... group by... having... order by.. limit [offset,] (rows)
- 執行順序:from... where...group by... having.... select ... order by... limit
mysql> select host,user from user;
SELECT host,user,password FROM user;