---
# System prepended metadata

title: 主鍵、外來鍵、inner join 小節作業
tags: [後端資料庫體驗營]

---

## 課堂筆記
一個表格只能有一個主鍵(PK)，但可以有多個外來鍵(FK)。
口訣：多的要設計成外來鍵，例如：一個部門會有多個員工。

主鍵(PK)：
➊ 必須是唯一值，不能重複。
➋ 不能是Null值，但外來鍵可以。
➌ 設定後不應再更動。

外來鍵(FK)：
➊ 當資料需要關聯到其他表格時才會用到。
➋ 必須對應到被參考資料表的主鍵。
➌ 命名通常會用'參考資料表_id'的格式。

[Postgres SQL指令](https://hackmd.io/@HCZvma86RdqPySqRGogXRA/ryZHj-v-yl)
<br>

## 作業一：拯救明華國小的資料庫，哪個欄位適合變成外來鍵？
![image](https://hackmd.io/_uploads/S1l6uz8-yx.png)

>[!TIP]思考方式
>[miro資料庫關聯圖](https://miro.com/app/board/uXjVLJydqsQ=/?share_link_id=240893456501)
>因為一個班級有多個學生、一個性別有多個學生，所以「班級」、「性別」是外來鍵。建立students、class、genders資料表，最後再合併顯示資料。
### 建立class資料表，新增資料
```
--製作資料表
CREATE TABLE class(
    c_id SERIAL PRIMARY KEY,
    c_name VARCHAR(50)
);
--新增資料
INSERT INTO class(c_name)VALUES
    ('三年一班'),
    ('三年二班');
```
### 顯示class資料表
```
SELECT 
    c_id AS 班級編號,
    c_name AS 班級
FROM class;
```
![image](https://hackmd.io/_uploads/Sk6sr9XZ1l.png)
### 建立genders資料表，新增資料
```
--製作資料表
CREATE TABLE genders(
    g_id SERIAL PRIMARY KEY,
    gender VARCHAR(50)
);
--新增資料
INSERT INTO genders(gender)VALUES
('女'),
('男');
```
### 顯示genders資料表
```
SELECT 
    g_id AS 性別編號,
    gender AS 性別  
FROM genders;
```
![image](https://hackmd.io/_uploads/BknZPc7Zkl.png)
### 建立students資料表，新增資料
```
--製作資料表
CREATE TABLE students(
  st_id SERIAL PRIMARY KEY,
  st_name VARCHAR(50),
  class_id INTEGER,  --因為要顯示class資料表的PK，所以資料類型是INTEGER
  gender_id INTEGER, --因為要顯示genders資料表的PK，所以資料類型是INTEGER
  age INTEGER,
  FOREIGN KEY(class_id)REFERENCES class(c_id), --外來鍵
  FOREIGN KEY(gender_id)REFERENCES genders(g_id) --外來鍵
);
--新增資料
INSERT INTO students(st_name,class_id,gender_id,age)VALUES
('小明',1,2,8),
('小華',2,1,9),
('小美',1,2,8),
('小強',1,1,8),
('小智',2,2,9);
```
![image](https://hackmd.io/_uploads/SyNAmf8Z1l.png)
### 顯示students資料表
```
SELECT 
  students.st_id AS 學生編號, --資料表.欄位名稱
  students.st_name AS 姓名,
  class.c_name AS 班級,
  genders.gender AS 性別,
  students.age AS 年齡
  
FROM students --只寫主表

INNER JOIN class ON students.class_id=class.c_id --不用加逗號或分號
INNER JOIN genders ON students.gender_id=genders.g_id;
```
![image](https://hackmd.io/_uploads/rJqs7fIb1g.png)
<br>

## 作業二：第一題的延伸，多了一個班級老師
![image](https://hackmd.io/_uploads/rk1PYM8Z1l.png)
>[!TIP]思考方式
>students資料表要建立一欄「班級老師」，然後更新students資料表每一筆資料的老師名字。最後再合併顯示students、class、genders資料表。
### students資料表新增teacher_name欄位(欄位內的資料是Null)
```
ALTER TABLE students --不用加逗號或分號 要新增欄位的資料表
ADD COLUMN teacher_name VARCHAR(50); --欄位名稱 資料類型
```
### 更新students資料表teacher_name欄位資料
```
UPDATE students
SET teacher_name='廖淯杰'
WHERE st_name='小明';

UPDATE students
SET teacher_name='卡斯伯'
WHERE st_name='小華';

UPDATE students
SET teacher_name='查理'
WHERE st_name='小美';

UPDATE students
SET teacher_name='麥可'
WHERE st_name='小強';

UPDATE students
SET teacher_name='李燕容'
WHERE st_name='小智';
```
### 顯示資料(合併students、class、genders資料表)
```
SELECT 
  students.st_id AS 學生編號, 
  students.st_name AS 姓名,
  class.c_name AS 班級,
  students.teacher_name AS 班級老師,
  genders.gender AS 性別,
  students.age AS 年齡
  
FROM students 

INNER JOIN class ON students.class_id=class.c_id 
INNER JOIN genders ON students.gender_id=genders.g_id;
```
![image](https://hackmd.io/_uploads/B1ekpG7L-kl.png)

<br>

## 作業三：小孩的家庭歸類資料庫，父母資料一值重複實在討厭！
![image](https://hackmd.io/_uploads/HyQXXX8Zkx.png)
>[!TIP]思考方式
>[miro資料庫關聯圖](https://miro.com/app/board/uXjVLJydqsQ=/?share_link_id=240893456501)
>建立parents資料表，然後students資料表新增一欄「家長編號 p_id(foreign key)」，再更新students資料表每一筆資料的家長編號資料。最後合併顯示students和parents資料表。
### 建立parents資料表，新增資料
```
CREATE TABLE parents(
  p_id SERIAL PRIMARY KEY,
  p_name VARCHAR(50),
  p_phone INTEGER,
  p_gender VARCHAR(50)
);

INSERT INTO parents(p_name,p_phone,p_gender)VALUES
('王大祥',0973254254,'男'),
('王曉如',0955717855,'女');
```
### students資料表新增p_id欄位，設為FK
```
ALTER TABLE students --要新增欄位的資料表
ADD COLUMN p_id INTEGER, --欄位名稱 資料類型
ADD FOREIGN KEY(p_id) REFERENCES parents(p_id);  --外來鍵
```
### 更新students資料表p_id欄位資料
```
UPDATE students
SET p_id=1
WHERE st_id IN(1,3,5);

UPDATE students
SET p_id=2
WHERE st_id IN(2,4);
```
### 顯示資料(合併students、parents資料表)
```
SELECT 
    students.st_id AS 小孩編號,
    students.st_name AS 姓名,
    parents.p_name AS 父母名稱,
    parents.p_phone AS 父母電話,
    parents.p_gender AS 父母性別
FROM students
INNER JOIN parents ON students.p_id=parents.p_id;
```
![image](https://hackmd.io/_uploads/HJt1QVL-kl.png)

<br>

## 延伸作業：學校新開設了音樂班，聘請了一位美女老師擔任班導，王大祥家長的小孩都想轉到音樂班就讀。
>[!TIP]思考方式
>class資料表先新增音樂班，然後students資料表篩選王大祥後，更新class_id、teacher_name欄位資料，最後合併顯示資料。
### class資料表新增音樂班
```
INSERT INTO class(c_name)VALUES
    ('音樂班');
```
### 更新王大祥的老師和班級資料
```
UPDATE students
SET teacher_name='美女老師'
WHERE p_id=1;

UPDATE students
SET class_id=3
WHERE p_id=1;
```
### 顯示資料(合併students、class、genders、parents資料表)
```
SELECT 
  students.st_id AS 學生編號, 
  students.st_name AS 姓名,
  class.c_name AS 班級,
  students.teacher_name AS 班級老師,
  genders.gender AS 性別,
  students.age AS 年齡,
  parents.p_name AS 父母名稱
  
FROM students 

INNER JOIN class ON students.class_id=class.c_id 
INNER JOIN genders ON students.gender_id=genders.g_id
INNER JOIN parents ON students.p_id=parents.p_id;
```

![image](https://hackmd.io/_uploads/HyeV1rU-ke.png)
