MySQL 的 SQL 筆記

主鍵

選取主鍵的一個基本原則是:不使用任何業務相關的字段(id)作爲主鍵。修改了主鍵,會造成一系列的影響

類型:

  1. 自增整數類型(id):BIGINT NOT NULL AUTO_INCREMENT
  2. 全局唯一 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 DEFAULT 0 COMMENT "班級 ID",
  `name` varchar(100) NOT NULL DEFAULT '' COMMENT "姓名",
  `gender` varchar(1) NOT NULL DEFAULT '男' COMMENT "性別",
  `score` int(11) NOT NULL DEFAULT 100 COMMENT "分數",
  `created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
  `updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT "學生表";

DESC students; // describe,查看錶結構

SHOW CREATE TABLE students; // 查看創建表的語句

DROP TABLE students; // 刪除表
  • bigint(20) 後面的 20 指的是字段最長長度,只是起提示作用。bigint 8 字節,最長不超過 20 位(922億億)
  • NOT NULL:插入數據時,必須有值
  • CHARSET( character set ) utf8 與 utf8mb4 的區別,char utf8 默認爲 3 個字節,utf8mb4 默認爲 4 個字節
  • COLLATE=utf8mb4_0900_ai_ci
  • 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 students MODIFY COLUMN birth VARCHAR(20) DEFAULT '' NOT NULL; // 設置默認值爲 ''
ALTER TABLE studens DROP COLUMN birthday; // 刪除 birthday 列
  • https://www.w3schools.com/sql/sql_alter.asp
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

事務有四大特性:

  • 原子性(Atomicity):不可分割,要麼成功,要麼失敗;
  • 一致性(Consistency):事務完成後,所有數據的狀態是一致的;
  • 隔離性(Isolation):併發執行的事務,對數據的操作要具有隔離性;
  • 持久性(Durability):事務完成後,數據就持久化到數據庫中

事務有隔離性有級別,共 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)


INSERT INTO students(id, name) VALUES (1, 'Alice');
select @@session.transaction_isolation # 查看隔離級別
SET @@session.transaction_isolation = 'READ-UNCOMMITTED'; # 切換隔離級別讀爲提交

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 INSERT INTO students(id, name) values(99, Alice) // 失敗
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;

image-20191126122815557

SELECT host,user,password FROM user;

延伸閱讀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章