# SQL
# SQL 基礎
SQL : Structured query language 結構查詢語言
常見有 Oracle / MSSQL / MySQL / PostgreSQL / SQLite (前二為付費系統)
- 除 SQLite 外, 其餘為 DataBase server, server 又可稱 connection pool, 而一個 server 可以有好幾個 database, 而一個 database 則可以有好幾個資料表 (table)
- SQLite 則為檔案型, 一個檔案就是一個 database, 一樣可以有好幾個 table, 但同一時間可以連線的數量少 (編輯保護的關係)
**R**elational **D**ata**b**ase **M**anagement **S**ystem 關連式資料庫 RDBMS
## [SQL 注入 (injection)](https://developer.mozilla.org/zh-TW/docs/Glossary/SQL_Injection)
是一種常見的資料庫攻擊技術,其目的是通過在應用程式中注入惡意的SQL語句,以繞過應用程式的安全機制,從而對資料庫進行非法操作或者取得機敏資料。
## DDL / DML / DQL
分別為三種語言, 為構築 SQL 的基本功能
### DDL (**D**ata **D**efinition **L**anguage 資料定義語言)
- 定義 SQL 的結構與組件
- 主要為 CREATE、ALTER 和 DROP 等, 用於創建, 修改, 刪除等
- 對象為資料表
### DML (**D**ata **M**anipulation **L**anguage 資料操作語言)
- 操作 SQL 數據
- 主要為 INSERT、UPDATE 和 DELETE 等, 用於增、刪、改數據。
- 對象為數據
### DQL (**D**ata **Q**uery **L**anguage 資料查詢語言)
- 查詢 SQL 數據
- 主要為 SELECT 用於查詢數據
# **SQL 語法**
SQL 語法是建立於 SQL 92 (但各家廠商各有客制
需了解C新增、R查詢、U更新、D刪除與交叉查詢
```sql
create database 資料庫名字;
//建立資料庫
drop database 資料庫名字;
//刪除資料庫, 直接掰掰, 無法救回
```
可寫一行, 也可分段寫, 結尾的分號要寫以免多行時出現意外
大小寫不限制, 但在 lunix 中有區分大小寫, 建議使用一種種類後就不要混用
## 資料型態
1. 字串型態(String Types)
- CHAR(n) : 固定長度字串, 若未滿長度則會補上空白, 超過可能會截斷或出錯 (無法寫入)
- VARCHAR(n) : 變動長度字串, 多少字就存多少字, 會有額外 1 byte 紀錄長度 (此byte不算在長度內)
- TEXT : 長字串, 用於存長文章
可變長度的字串且希望節省儲存空間時, 用`VARCHAR`
而長度固定且相對較小,或注重查詢效能方面,可以考慮使用`CHAR`
2. 數字
- decimal : 十進位數字
- integer : 整數
3. 日期時間
- date : 日期,格式為'YYYY-MM-DD'。
- datetime : 日期和時間的組合,格式為'YYYY-MM-DD HH:MM:SS'。
4. blob = binary large object : 二進制大型物件, 圖像、音頻或影片
5. 其他 (可藉由 GPT 查詢, 總類繁複)
## 基礎操作 (base on SQLite)
### 資料庫
```sql
CREATE DATABASE some_db; //創立資料庫 (some_db 為自定義的資料庫名稱
```
```sql
DROP DATABASE some_db; //刪除資料庫, 直接掰掰, 沒救援手段
```
可只寫一行, 也可以分段寫, 最後的分號要寫, 以免多行時出意外
### 資料表
新增資料表
```sql
CREATE TABLE some_table ( //some_table 為自定義的表單名稱, 下放輸入各欄位資訊
id INT NOT NULL AUTO_INCREMENT, //id 此欄為整數, 不可為空, 自動生成序號
name VARCHAR(100) NOT NULL, //名字 此欄最多100字, 不可為空
gender CHAR(1), //性別 此欄固定皆為一個字
description TEXT, //敘述 此欄為長串文字
PRIMARY KEY(id) //此資料表的主 key 為 id
)
```
刪除資料表
```sql
DROP TABLE some_table; //建議直接用圖形介面點選就好
```
追加欄位
```sql
ALTER TABLE some_table
ADD COLUMN some_item VARCHAR(5); //新增一個為 some_item 的欄位, 並記錄最多五字元的項目
```
刪除欄位
```sql
ALTER TABLE some_table
DROP COLUMN some_item; //刪除 some_item 的欄位,
```
## 資料操作 (base on SQLite)
### 新增資料 (C)
```sql
INSERT INTO some_table
(name, age, gender, description)
VALUES
('名字', 20, 'F', "文字要加引號, 數字不用, 有需要符號用反斜線跳脫"); //一個項目對一個值
```
省略欄位
```sql
INSERT INTO some_table
VALUES
('名字', 20, 'F', "文字要加引號, 數字不用, 有需要符號用反斜線跳脫"); //同一個蘿菠一個坑
```
寫入部分欄位
```sql
INSERT INTO some_table
(description, age, name)
VALUES
("文字要加引號, 數字不用, 有需要符號用反斜線跳脫", 20, '名字'); //可不依順序寫, 但項目同依序填入
```
### 查詢資料 \(R)
```sql
SELECT * //星號代表全部欄位, 此處可填入欄位名稱
FROM some_table
```
過濾資料
追加條件就可以用 AND 追加
```sql
SELECT *
FROM some_table
WHERE age = 20; //在 some_table 內找尋全部欄位, age = 20 的挑出來
WHERE age = 20 AND gender = 'F' // 同上條件, 但必須是女性
```
查詢空值
```sql
SELECT *
FROM some_table
WHERE age IS NULL; //some_table 內 age 為空值
```
查詢關鍵字
將 = 或 is 改成 like
% 代表字元, %我, 代表我前面有其他字, 我%代表我後面有字, %我%, 代表前後有字
```sql
SELECT *
FROM some_table
WHERE name LIKE '%英%'; //名字裡有 英 的人
```
網站的模糊查詢
網站的模糊是以不一樣的方式運作, 一般的查詢系統與模糊比對的查詢對比如下 :
- 一般:User -> 關鍵字 -> App -> DB -> result
- 模糊:User -> 關鍵字 -> App -> (DB索引) -> DB -> result
通常業界使用 ElasticSearch 來當 DB 索引 (簡單說就是 DB 的 DB
區間
```sql
SELECT *
FROM some_table
WHERE age BETWEEN 10 AND 25; //也可用以下
WHERE age >= 10 AND age <=25
```
注意 “跟” ,如列出成績 “A” 跟 “B”, 但實際上不會有人同時有 A 跟 B 所以要用 or
```sql
SELECT *
FROM some_table
WHERE grade = "A" or grade = "B"; // 也可用以下
WHERE grade IN ('A', 'B');
```
不是 (SQL 內 <> 為不等於的意思 )
```sql
SELECT *
FROM some_table
WHERE grade <> "A" AND grade <> "B"; // 也可用以下
WHERE grade NOT IN ('A', 'B');
```
### 更新資料 (U)
```sql
UPDATE some_table //哪個表
SET age = 10 //要改什麼
WHERE id = 25 //條件(目標)
// 如果此處沒有 WHERE 則是全部資料的 age 改成 10
```
多筆更新
```sql
UPDATE some_table
SET age = 10, gender = "M", grade = "C" //要改什麼用逗號隔開
WHERE id = 25
```
也可使用運算符號子
```sql
UPDATE some_table
SET age += age // age 加一歲
WHERE id = 25
```
### 刪除資料 (D)
```sql
DELETE FROM some_table
WHERE grade = 'C'; //將成績C的通通刪掉
```
## 進階操作
### 計數 (計算總數)
```sql
SELECT COUNT(*)
FROM some_table
WHERE grade = 'A' //計算成績為 A 的總人數
```
### 加總、平均
```sql
SELECT SUM(age) // 用 SUM 計算有成績且成績A的總年齡
FROM some_table
WHERE grade = 'A' AND age IS NOT NULL;
```
```sql
SELECT AVG(age) // 用 AVG 計算有成績且成績A的平均年齡
FROM some_table
WHERE grade = 'A' AND age IS NOT NULL;
```
### 最大最小值
```sql
SELECT MAX(age) //最小則用 MIN
FROM some_table
```
### 分組
```sql
SELECT grade, SUM(age) // 顯示成績, 並依成績分組後的年齡加總
FROM some_table
GROUP BY grade; //依成績分組
```
### 挑掉重複
```sql
SELECT DISTINCT grade // 顯示出總共有哪些成績
FROM some_table;
```
### 排序
```sql
SELECT *
FROM some_table
ORDER BY birthday ASC; // 依生日排序
```
ASC 可以不寫, 本身就是以升冪排序為預設 ; DESC 則為降冪排序
### 數量限制
```sql
SELECT *
FROM some_table
ORDER BY grade
LIMIT 5; //依成績排序, 並顯示前五名
```
# ER 圖 (Entity-Relationship Diagram)
實體關係圖是用來描述系統中**重要的個體**及**其間的關係**。
實體 : 是指用以描述真實世界的物件。
在實務需求上我們可以將 實體 轉換成各種資料表
關係 : 是指用來表示 一個實體 與 另一個實體 關聯的方式。
如 : 一對一關係 、一對多關係 、多對多關係。
超簡易繪製流程:
1. 掌握業務流程和規則
2. 從中抽出「實體」
3. 檢核抽出的「實體」是否有不足或多餘的
4. 最後設定實體的「關聯」
若多對多的資料關聯會由第三方表格紀錄 (join table)
## 鍵 KEY
### 主鍵 Primary Key / PK
- 資料表中 (table) 某一個欄位
- 不可為空值 (null)
- 獨一無二的值
### 外部鍵 Foreign Key / FK
- 資料表中 (table) 某一個欄位
- 可以參照另一個資料表主鍵
- 確認該資料與其他資料表的內容可以對起來
- 可以為空值, 也不需要獨一無二
外部鍵有其限制 :
1. 參照完整性 : 確保建立時, 此外部鍵存在於另一個資料表中, 如 :
訂單中, 外部鍵為購買顧客 ID, 需確保此 ID 在顧客的資料表內是真實存在的
2. 一致性 : 即表語表之間的數據一致性, 當在父表中更新或刪除時, 外鍵約束可以定義相應的操作, 於子表做相同資料的更新與刪除
3. 數據完整性 : 即防止無效或不一致的數據進入數據庫。
4. 約束條件 : 可以定義一些約束條件, 如級聯操作 (CASCADE)、禁止操作 (RESTRICT) 等, 以規定父表的紀錄產生變化時, 子表相關紀錄的處理方式
## 多表參照查詢
### 交叉查詢及操作
```sql
SELECT *
FROM score_table
WHERE student = // 從 score_table 找出 class_table 內為李某的 data
( // c 表的李某 id 會匯出至 s 表內查詢, 若 student 的資料對到則會顯示出來
SELECT studentid
FROM class_table
WHERE name = '李某'
);
```
也可多項目一起查詢
```sql
SELECT name, scroe
FROM score_table
WHERE student IN
(
SELECT studentid
FROM class_table
WHERE name IN ('李某','陳某')
);
```
### 交集 (join)
有分 inner / left / right (但SQLite 沒支援right)
Join 預設為 inner
```sql
SELECT *
FROM t1
JOIN t2 // 列出 t1 與 t2 兩兩相比的表, 總數為 t1數 * t2數
```
預設 inner 的狀況
```sql
SELECT *
FROM t1
JOIN t2
WHERE t1.username = t2.name //請依 t1 的 username 為底, 對照 t2 的 name, 一樣請列出
//此處 where 用 on 也可以
```
使用 left
```sql
SELECT *
FROM t1
LEFT JOIN t2
ON t1.username = t2.name
//此時 t1 表的內容會全數留下, 但在 t2 表內名字不符的會被屏棄, t1 內同名的會加入 t2 的資訊
//而 t1 沒有的相符名子的, t2 新增進來的欄位則以 null 填入
```
Join table 多表資料混合
```sql
SELECT b.*, h.name // 顯示戰鬥歷史全部的欄目與英雄表內的名字欄目
FROM battle_histories as b // 將戰鬥歷史的 table 以 b 代稱
JOIN heroes as h // 將英雄的 table 以 h 代稱
ON b.hero_id = h.id
```
可用 as 給予別名, 甚至不寫 as 也可以
```sql
SELECT b.*, h.name as 英雄 , m.name as 怪物 // 可改變最後顯示出來上方欄目的名稱
FROM battle_histories b
JOIN heroes h, monsters m
ON b.hero_id = h.id and b.monster_id = m.id // 三張表交叉查詢
```