---
# System prepended metadata

title: SQL學習
tags: [MySql]

---

# SQL學習

###### tags: `MySql`

> 簡單認識SQL
## :memo: SQL認識

:::info
:pushpin: [學習影片](https://www.youtube.com/watch?v=gvRXjsrpCHw) 
:::

### 認識表格 & 鍵 (tables & keys)

![](https://i.imgur.com/cTKVJhS.jpg)

- 藍色框: key (一般鍵值)
- 紅色框: primary key (主鍵)
- 綠色框: foreign key (外鍵)

#### 主鍵
具有唯一值，若主鍵內有重複地到的值，那會在拆出另一個主鍵來表示，直接該需要的數值是表格內的唯一值(圖片中Works_With部分)

#### 外鍵
表格內連結其他表主鍵的key值，連結到的一定目標所在的表格的主鍵

### 創建資料庫 (0:37)

![](https://i.imgur.com/kaIqMut.png)

- 藍色文字: mySql的關鍵字，一般以大寫表示
- 紅色文字: 自定義名稱，一般會加上`反引號`來區分系統關鍵字
- 閃電符號: 選取打好的的指令後，按下該符號來執行，
- 最下方視窗顯示已執行的指令，中間顯示結果(SHOW DATABASES)

### 創建表格 (0:44)

- 資料型態介紹:
![](https://i.imgur.com/pDMzjZ9.png)

    1. INT: 整數型態 
    2. DECIMAL(m,n): 小數點數字
    第一個參數代表總共幾位數，第二個參數代表小數點站了幾位，如:2.33 要傳入(3,2)
    3. VARCHAR(10): 字串
    括號寫入可以存取字串的數量，寫10表示最多只能存10個字串元
    4. BLOB: Binary Large Object 存放二進制的資料，如:圖片、影片、檔案...等
    5. DATE: 'YYYY-MM-DD' 日期 2021-10-19
    6. TIMESTAMP: 'YYYY-MM-DD HH-MM-SS' 紀錄時間 2021-10-19 10-39-00
    
- 指令 創建表格:
    ```sql=
    CREATE TABLE `student`(
        `student_id` INT PRIMARY KEY,
        `name` VARCHAR(20),
        `major` VARCHAR(20),
        -- 主鍵設置也可以寫成: PRIMARY KEY(`student_id
    )
    -- 觀看表格:
    DESCRIBE `student`;
    -- 刪除表格
    DROP TABLE `student`;
    -- 新增屬性gpa到表格--
    ALTER TABLE `student` ADD `gpa` DECIMAL(3,2);
    -- 刪除屬性gpa
    ALTER TABLE `student` DROP COLUMN `gpa`;
    ```
    
### 儲存資料 (00:56)
```sql=
CREATE TABLE `student`(
	`student_id` INT PRIMARY KEY,
    `name` VARCHAR(20),
    `major` VARCHAR(20)
);
-- 列出所有student資料
SELECT * FROM `student`; -- 米字號代表全部
-- 新增資料至表格
INSERT INTO `student` VALUES(3, '小綠', NULL); -- VALUES()新增順序要根據創建表格時的排序
-- 新增表格 自定義屬性順序
INSERT INTO `student`(`major`,`student_id`) VALUES('歷史', 5);
```

### 限制、約束constraint (01:04:00)

```sql=
CREATE TABLE `student`(
    -- AUTO_INCREMENT 自動補上數字排序 就不用每次新增都要寫數字了
    `student_id` INT AUTO_INCREMENT,
    -- 不能是NULL值
    `name` VARCHAR(20) NOT NULL,
    -- DEFAULT 預設值
    `major` VARCHAR(20) DEFAULT '歷史',
    -- UNIQUE 每一個值都是唯一值
    `phone` INT UNIQUE, 
    PRIMARY KEY(`stundent_id`)
);
-- 不用給予數字排序 會自動新增
INSERT INTO `student`(`name`,`phone`) VALUES('小王',097755777);
```

### 修改、刪除資料(01:11:00)

```sql=
-- 選擇要更新的表格  
UPDATE `student`
-- SET 要更新的內容
SET `name`= '小輝',  `major` = '日文'
-- WHERE 增加條件判斷
WHERE `student_id` = 1;

DELETE FROM `student`
WHERE `name` = "小輝" AND `major` = '日文';  -- AND 且

-- 設定數字範圍
DELETE FROM `student`
WHERE `sore` <= 50;
```

### select 選擇資料(01:33:00)
```sql=
SELECT * 
FROM `student` 
--ORDER BY 排序默認升序(ASC) 加上 DESC 為降序
ORDER BY `sore` DESC; 
 -- 限制輸出數
LIMIT 2; 
-- 條件判斷:WHERE 
-- 回傳只有主修是日文的
WHERE `major` = "日文"; 
-- <> 一對大小於是mysql的不等於!
WHERE `major` = '日文' OR `score` <> 66;  
-- where 判斷的另一種寫法in (or的寫法)
WHERE `major` IN('統計', '歷史');
-- 就等於下面:
WHERE `major` = '統計'  OR `major` = '歷史'
```

### 建立公司表格
![](https://i.imgur.com/6rhJpSw.jpg)

1. 創建 員工 表格:需要先有表格與屬性才能設定外鍵
```sql=
CREATE TABLE `employee`(
	`emp_id` INT PRIMARY KEY,
    `name` VARCHAR(20),
    `birth_date` DATE,
    `sex` VARCHAR(1),
    `salary` INT,
    -- 以下為外鍵但其他表格尚未建立，所以先創建就好
    `branch_id` INT, -- 隸屬於哪個部門 
    `sup_id` INT -- 主管單位 
);
```


2. 創建 部門 表格:外建設定
```sql=
CREATE TABLE `branch`(
    `branch_id` INT PRIMARY KEY,
    `branch_name` VARCHAR(20),
    `manager_id` INT,
    FOREIGN KEY (`manager_id`) REFERENCES `employee`(`emp_id`) ON DELETE SET NULL
);
```

3. 設定 員工 表格內的外鍵(branch_id、sup_id)
```sql=
-- 重新設定外鍵

-- 選擇要改變的表格
ALTER TABLE `employee`

-- 將原本屬性變為外鍵(屬性名)
ADD FOREIGN KEY(`branch_id`)

-- 連結的目標 `表格名`(`屬性`)
REFERENCES `branch`(`branch_id`)
ON DELETE SET NULL;

ALTER TABLE `employee`
ADD FOREIGN KEY(`sup_id`)
REFERENCES `employee`(`emp_id`)
ON DELETE SET NULL;
```

4. 創建 顧客 表格
```sql=
CREATE TABLE `client`(
    `client_id` INT PRIMARY KEY,
    `client_name` VARCHAR(20),
    `phone` VARCHAR(20)
);
```

5. 創建 銷售金額 表格
```sql=
CREATE TABLE `works_with`(
    `emp_id` INT,
    `client_id` INT,
    `total_sales` INT,
    -- 兩個主鍵
    PRIMARY KEY(`emp_id`, `client_id`),
    -- 設定兩個為外鍵
    FOREIGN KEY (`emp_id`) REFERENCES `employee`(`emp_id`) ON DELETE CASCADE,
    FOREIGN KEY (`client_id`) REFERENCES `client`(`client_id`) ON DELETE CASCADE
);
```

#### 設定資料
先從沒有關聯到其他表格的主鍵開始創建，不然會錯誤

1. 如果先新增員工的資料，會因為還沒有部門(branch)的資料的外鍵出錯
所以要先:
```sql=
INSERT INTO `branch` VALUES(1,'研發',null);
INSERT INTO `branch` VALUES(2,'行政',null);
INSERT INTO `branch` VALUES(3,'資訊',null);
```
2. 再來新增員工
```sql=
-- 新增員工資料
INSERT INTO `employee` VALUES(206,'小黃','1998-10-08','F',50000,1,NULL);
INSERT INTO `employee` VALUES(207,'小綠','1985-09-18','M',40000,2,206);
INSERT INTO `employee` VALUES(208,'小黑','2000-01-22','M',31000,3,206);
INSERT INTO `employee` VALUES(209,'小白','1997-03-18','F',39000,3,207);
INSERT INTO `employee` VALUES(210,'小藍','1983-05-10','F',84000,1,207);
```

3. 依序更改部門中的marnger_id
```sql=
-- 更新marnger_id 的值
UPDATE `branch`
SET `manager_id` = 208 -- 206 / 207 / 208
WHERE `branch_id` = 3; -- 1 / 2 / 3
```

4. 新增顧客資料
```sql=
INSERT INTO `client` VALUES(400,'阿狗',25468791);
INSERT INTO `client` VALUES(401,'阿福',26987451);
INSERT INTO `client` VALUES(402,'旺來',77222456);
INSERT INTO `client` VALUES(403,'阿花',54879863);
INSERT INTO `client` VALUES(404,'瓜拉',78954123);
INSERT INTO `client` VALUES(405,'艾拉斯',78400091);

```

5. 新增商品資料
```sql=
INSERT INTO `works_with` VALUES(206,400,'700000');
INSERT INTO `works_with` VALUES(207,401,'24000');
INSERT INTO `works_with` VALUES(208,402,'98000');
INSERT INTO `works_with` VALUES(208,403,'48000');
INSERT INTO `works_with` VALUES(210,404,'87400');
```

## 取得公司資料
1. 取得所有員工資料
```sql=
SELECT * FROM `employee`;
```
2. 取得所有客戶資料
```sql=
SELECT * FROM `client`;
```
3. 按薪水低到高取得員工資料
```sql=
SELECT * FROM `employee` ORDER BY `salary`;
```
4. 取得薪水前三高的員工
```sql=
SELECT * FROM `employee` ORDER BY `salary`  DESC
LIMIT 3;
```
5. 取得所有員工的名字
```sql=
SELECT `name` FROM `employee`;
```
6. 取得所有員工重複的所屬單位
DISTINCT 不重複
```sql=
SELECT DISTINCT `sup_id` FROM `employee`;
```

## aggregate function 聚合函數
1. 取得員工人數
```sql=
SELECT COUNT(*) FROM `employee`;
-- 5
```
count()括號裡面可以放屬性名，計算該屬性有值的數量
```sql
SELECT COUNT(`sup_id`) FROM `employee`;
-- 輸出四，因表格內有一位為NULL
```
2. 取得所有出生於 1970-01-01 後的女性員工人數
```sql=
SELECT COUNT(*) FROM `employee`
WHERE `birth_date` > '1970-01-01' AND `sex` = 'F';
-- 3
```
3. 取得所有員工的平均薪水 AVG(屬性) 取平均
```sql=
SELECT AVG(`salary`) FROM `employee`;
```
4. 取得所有員工薪水的總和 SUM(屬性) 取總和
```sql=
SELECT SUM(`salary`) FROM `employee`;
```
5. 取得薪水最高的員工 MAX(屬性) 取最高
```sql=
SELECT MAX(`salary`) FROM `employee`;
```
6. 取得薪水最低的員工 MIN(屬性) 取最低
```sql=
SELECT MIN(`salary`) FROM `employee`;
```

## 萬用字元 wildcards 
**% 代表多個字元, _ 代表一個字元**

1. 取得電話號碼尾數是 123 的客戶 LIKE 判斷是否符合下述句 %不管前面有多少個字元 只要尾數是123者
```sql=
SELECT * FROM `client` WHERE `phone` LIKE '%123';
-- 可依照不同的位置做判斷，254%: 開頭是否為254，%798%: 中間數字是否有798
SELECT * FROM `client` WHERE `phone` LIKE '254%';
-- 中間是否有798
SELECT * FROM `client` WHERE `phone` LIKE '%798%';
```
2. 取得姓"艾"的客戶
```sql=
SELECT * FROM `client` WHERE `client_name` LIKE '艾%';
```
3. 取得生日在3月的員工 
五個底線 代表五個字元
```sql=
SELECT * FROM `employee` WHERE `birth_date` LIKE '_____03%';
```

## 聯集Union

1. 員工名字 union 客戶名字 
**union 可讀作合併**
tips:要使用union 所有的SELECT 屬性述都要一樣; 做合併的屬性，資料型態都要一樣 
```sql=
SELECT `name` FROM `employee`
UNION
SELECT `client_name` FROM `client`
UNION
SELECT `branch_name` FROM `branch`;
```
2. 員工id + 員工名字 union 客戶id + 客戶名字
加入AS後，UNION合併後輸出的屬性就為AS後面的名稱
```sql=
SELECT `emp_id` AS `total_id`, `name` AS `totoal_id` FROM `employee`
UNION
SELECT `client_id`, `client_name` FROM `client`;
```
3. 員工薪水 union 銷售金額
```sql=
SELECT `salary` AS `money` FROM `employee`
UNION
SELECT `total_sales` FROM `work_with`;
```

## JOIN 連結
可用於查詢連結相同屬性不同的表格
1. 取得所有部門經理的名字
```sql=
SELECT `employee`.`emp_id`, `employee`.`name`, `branch`.`branch_name`
FROM `employee` LEFT JOIN `branch`
-- FROM `employee` RIGHT JOIN `branch`
ON `employee`.`emp_id` = `branch`.`manager_id`; --  
```
- ON 後面接符合條件
- LEFT JOIN: 在關鍵字LEFT JOIN左邊的表格會不管條件有沒有成立皆輸出 右邊則是遵守條件，若不成立會回傳NULL。
- RIGHT JOIN: 與LEFT JOIN相反


## 子查詢 subquery
在一個查詢語句中加入另一個查詢語句

1. 找出研發部門的經理名字
利用子查詢結果 經理id找出在branch哪一個
```sql=
SELECT `name`
FROM `employee`
WHERE `emp_id` = (
	-- 子查詢:找到研發部門經理的id
	SELECT `manager_id`
	FROM `branch`
	WHERE `branch_name` = '研發'
);
```

2. 找出對單一單位客戶銷售金額超過50000的員工名字 (WORKS_WITH.total_sales > 50000) 

```sql=
-- 找出員工id後再找到他的名字
SELECT `name`
FROM `employee`
WHERE `emp_id` IN (
	-- 子查詢:先找超過5萬
	SELECT `emp_id`
	FROM `works_with`
	WHERE `total_sales` > 50000
);
```
這邊用 IN 是因為子查詢出來的結果不只一個所有用IN將所有可能列出。
單純只有等於會報錯，等於只能一個結果的時候用喔!

## ON DELETE
```sql=
CREATE TABLE `works_with`(
    `emp_id` INT,
    `client_id` INT,
    `total_sales` INT,
    PRIMARY KEY(`emp_id`, `client_id`),
    FOREIGN KEY (`emp_id`) REFERENCES `employee`(`emp_id`) ON DELETE SET NULL,
    FOREIGN KEY (`client_id`) REFERENCES `client`(`client_id`) ON DELETE CASCADE
);
```
- ON DELETE SET NULL:
被刪除時，將此表格存留但值設為NULL
- ON DELETE CASCADE
被刪除時，將此表格通通刪掉

```sql=
-- 刪除
DELETE FROM `employee`
WHERE `emp_id` = 207;
```
會發現: 被刪除的員工ID同時也是manager_id，同時在部門manager_id被刪除了
![](https://i.imgur.com/MzGGYzF.png)

然後設定 ON DELETE CASCADE的 員工表格
![](https://i.imgur.com/7LEpQGk.png)
編號207被砍了

