Table of contents
1 Table 相關語法
1.1 創建 table
1CREATE TABLE tbl_person (
2 entity_id INT IDENTITY(1, 1),
3 name VARCHAR(255) NOT NULL,
4 email VARCHAR(255) NOT NULL,
5 created_at DATETIME NOT NULL DEFAULT GETDATE(),
6 updated_at DATETIME NOT NULL DEFAULT GETDATE(),
7
8 PRIMARY KEY (entity_id),
9 CONSTRAINT UQ_person UNIQUE (email)
10);
1.2 刪除 table
DROP TABLE IF EXISTS tbl_person;
1.3 新增紀錄
INSERT INTO tbl_person VALUES ('Alice', 'alice@gmail.com', GETDATE(), GETDATE());
INSERT INTO tbl_person (name, email) VALUES ('Bob', 'bob@gmail.com');
註:
IDENTITY
column 唔應該入,應該由 DB 自動生成。
- 如果
VALUES
前面有 column list,有 DEFAULT
既 columns 可以選擇明確提供或者唔提供,唔提供既話 DB 就會用左 CREATE TABLE
裡面 column definition 既 DEFAULT
(例子中 create_at
既 default value 就係 built-in function GETDATE()
)。
1.4 查詢紀錄
1.4.1 一般查詢
SELECT * FROM tbl_person;
1SELECT
2 entity_id,
3 name,
4 email,
5 created_at
6FROM tbl_person
7WHERE entity_id = 1;
Pagination(分頁):
SELECT *
FROM tbl_person
ORDER BY entity_id
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY; -- NEXT、FIRST 係同義
1.4.2 多 tables 查詢
同其他 table 連起黎:
1CREATE TABLE tbl_friend (
2 entity_id INT IDENTITY(1, 1),
3 person_entity_id INT NOT NULL,
4 name VARCHAR(255) NOT NULL,
5
6 PRIMARY KEY (entity_id),
7 INDEX IX_friend (entity_id, person_entity_id)
8);
9
10INSERT INTO tbl_friend (person_entity_id, name) VALUES (1, 'Mick');
11
12SELECT
13 p.name,
14 f.name
15FROM
16 tbl_person p,
17 tbl_friend f
18WHERE
19 p.entity_id = f.person_entity_id
20AND p.name = 'Alice'
1.4.3 帶鎖查詢
如果同時有多過一個程式需要查詢然後更新同一行紀錄,我地可以用悲觀鎖。當兩個程式同時執行以下 SQL,只有一個程式可以立即查詢到相關紀錄,而另一個程式就會一直等待,直到攞到鎖既程式完成曬 transaction,咁佢先會攞到個鎖。
1BEGIN TRANSACTION;
2
3SELECT *
4FROM tbl_person
5WITH (
6 UPDLOCK,
7 ROWLOCK
8)
9WHERE entity_id = 2;
如果 WHERE
裡面既條件唔係針對 primary key column 既 value,咁我地就要自己起 index,然後用 WITH (UPDLOCK, INDEX(<index name>))
,否則 SQL Server 會鎖埋唔 match WHERE
條件既紀錄,更有可能鎖曬成個 table 既紀錄。
1.5 刪除部分或所有紀錄
以特定條件刪除 table 內紀錄:
DELETE FROM tbl_person WHERE entity_id = 1;
刪除 table 內所有紀錄:
DELETE FROM tbl_person;
註:
DELETE
係 DML 語句。
- 所以
DELETE
係可以喺 transaction 裡面執行,自然就可以 rollback。
1.6 清空所有紀錄
TRUNCATE TABLE tbl_person;
註:
TRUNCATE
係 DDL 語句,有別於 DELETE
。
- 所以
TRUNCATE
係唔可以喺 transaction 裡面執行,自然就唔可以 rollback。
TRUNCATE
所產生既 transaction log 會遠少過 DELETE
。
TRUNCATE
唔會觸發 trigger。
2 Sequence 相關語法
2.1 創建 sequence
CREATE SEQUENCE seq_generator START WITH 1000 MINVALUE 1000 MAXVALUE 9999 CYCLE;
2.2 更改 sequence
ALTER SEQUENCE seq_generator RESTART WITH 2000;
2.3 獲取下一個 sequence value
SELECT NEXT VALUE FOR seq_generator;
3 Trigger 相關語法
3.1 創建或更新 trigger
3.1.1 由更新紀錄觸發
1CREATE OR ALTER TRIGGER trg_person
2ON tbl_person
3FOR UPDATE AS
4BEGIN
5 UPDATE p
6 SET updated_at = GETDATE()
7 FROM tbl_person p, inserted
8 WHERE p.entity_id = inserted.entity_id
9END;
10GO
解釋:當 tbl_person
既紀錄被更新,將會觸發呢個 trigger 去更新相關紀錄既 updated_at
column 做當前系統時間。
4 其他語法
4.1 執行動態 SQL
如果 table 名、 column 名等 SQL 元素需要動態 values,咁就要用呢個方法:
-- 假設 values 從某個 table 取得
DECLARE @columns VARCHAR(100) = 'name, email';
DECLARE @tableName VARCHAR(100) = 'tbl_person';
EXEC('SELECT ' + @columns + ' FROM ' + @tableName);
5 查詢系統 tables
5.1 查詢 table list
SELECT * FROM sys.tables;
5.2 查詢 table 既 column 結構
1SELECT
2 CAST(c.name AS VARCHAR) columnName,
3 CAST(typ.name AS VARCHAR) dataType,
4 c.max_length maxLength,
5 c.precision,
6 c.scale
7FROM
8 sys.all_columns c,
9 sys.tables tbl,
10 sys.types typ
11WHERE
12 c.object_id = tbl.object_id
13AND c.system_type_id = typ.system_type_id
14AND tbl.name = 'table_name'
15ORDER BY c.column_id;
6 查看 SQL execution plan、index 使用情況(優化 SQL 用)
SQL Server 冇 MySQL/MariaDB 既 EXPLAIN
,只能透通過 SQL Server Management Studio(SSMS)黎睇 estimated execution plan 以及 actual execution plan。
喺 SSMS:
- 顯示 estimated execution plan
- Highlight 然後 right-click 句 SQL
- 撳 Display Estimated Execution Plan
- 佢會顯示 execution plan
- 顯示 actual execution plan
- Right-click 輸入 SQL query 既任何空白位置
- 撳 Include Actual Execution Plan
- 每當 execute 一句 SQL,佢就會顯示 execution plan
Execution plan 應該會包含 2
個或以上既圖示,我地可以用 mouse hover 啲圖示睇下佢頭頂寫咩。好籠統咁講:
- 如果圖示有 index seek 字眼就會用上 index
- 如果圖示有 index scan 或者 table scan 字眼就唔會用上 index。
非專業見解:
- Index seek 比 index scan 或者 table scan 效能要好。
SELECT *
- 如果令 query result 既 columns 包括左個 table 定義既 indexes 冇既 columns,咁佢個 execution plan 右邊可能會出現
2
個步驟(3
個或以上既圖示),可以係 index seek 完再 RID lookup 或者 key lookup,不過實際情況要視乎個 table schema/definition。
LIKE
- 如果
WHERE
clause 係對 VARCHAR
column 用 LIKE 'xxx%'
,應該可以用到 index seek。
- 如果
WHERE
clause 係對 VARCHAR
column 用 LIKE '%xxx'
或者 LIKE '%xxx%'
,就用唔到 index seek。
- Type conversion
- 如果
WHERE
clause 對 INT
column 用 LIKE '1%'
,就用唔到 index seek,而 execution plan 既 SELECT 圖示會顯示黃色三角形以及關於 type conversion 既 warning。
WITH (FORCESEEK)
- 呢個 hint 可以令
1
個 scan 既步驟拆開成 2
個步驟——seek 以及 lookup。
SELECT email FROM tbl_person WITH (FORCESEEK) WHERE email LIKE 'xxx%';
參考資料: