---
# System prepended metadata

title: '[.NET 筆記 006] MS SQL Server 資料庫設計'

---

## [.NET 筆記 006] MS SQL Server 資料庫設計

###### 📅 2026-04-13

### Step-1. 下載 MS SQL Server
1. 搜尋 "sql server download"

2. 找到微軟下載頁: https://www.microsoft.com/zh-tw/sql-server/sql-server-downloads

3. 下載 SQL Server 2025 開發人員版本 > Standard (標準版)
![image](https://hackmd.io/_uploads/BkE3Ekc3Wl.png)

4. 安裝方式: Custom (自訂)

5. 語言: Chinese (Traditionaal) (繁體中文)

6. 安裝路徑: "C:\SQL2025"

7. 點擊: Install，等待 3 分鐘左右安裝

8. SQL Server 安裝中心

## Step-2. 安裝 MS SQL Server
1. 點擊: 左側 "安裝" > 右側 "新的 SQL Server 獨立安装或將功能新增至現有安裝"

2. 指定免費版本: 選 "Standard Developer" > 接受授權條款

3. 勾選: "使用 Microsoft Update 檢查更新"

4. 取消勾選: "適用於 SQL Server的 Azure 延伸模組" 

5. 特徵選取 > 功能: 只勾選 "資料庫引擎服務" (路徑: C:/ProgramFiles/Microsoft SQL Server)

6. 執行個體組態 > 選 "具名個體" > 填入自訂名稱: "SQL2025"
(執行個體識別碼: SQL2025)
(SQL Server 目錄: C:\Program Files\Microsoft SQL Server\MSSQL17.SQL2025)

7. 伺服器組態 > (預設)
![image](https://hackmd.io/_uploads/SJAiYJq3be.png)
(SQL Server Agent: NT Service\SQLAgent\$SQL2025)
(SQL Server Database Engine: NT Service\MSSQL$SQL2025)
(SQL Server Browser: NT AUTHORITY\LOCAL SERVICE)

8. 資料庫的引擎組態 > 驗證
(a) 選 "混合模式" 
(b) 指定 SQL Server 管理員 > 加入目前使用者
\(c) 輸入密碼 & 確認密碼: 填入 "Windows 登入密碼"

9. 準備安裝 > (預設)
(C:\Program Files\Microsoft SQL Server\170\Setup Bootstrap\Log\20260413_114235\ConfigurationFile.ini)

10. 點擊: 安裝

## Step-3. 安裝 SQL Server 管理工具 (SSMS, SQL Server Management Studio)
1. 點擊: 左側 "安裝" > 右側 "安裝 SQL Server 管理工具"
2. 自動以瀏覽器開啟網頁：https://learn.microsoft.com/zh-tw/ssms/install/install
3. 點擊: "Download SQL Server Management Studio 22 安裝器"
4. 下載並點擊 vs_SSMS.exe 後，若先前已安裝 Visual Studio 會跳轉到 "工作負載" > 點擊: 安裝
![image](https://hackmd.io/_uploads/rJfVFWc3-e.png)
(版本: 22.4.1)
(發行編號：22.4.1, 上映日期：2026年3月18日)
(連結: https://learn.microsoft.com/zh-tw/ssms/release-notes-22#22.4.1)

## Step-4. SSMS 基本操作
1. Windows 工具列 > 搜尋 > 輸入: "SSMS"，點擊: "SQL Server Management Studio 2022"

2. 回顧先前設定: 在先前的【Step 2. (6)】，已經將【執行個體組態】，設定為 "SQL2025"

3. 【連線】設定
![image](https://hackmd.io/_uploads/HkWQtMc2Wg.png)
* 伺服器名稱: ".\SQL2025"（必須在執行個體名稱前方加上 ".\"）
(PS: 點 . 代表本機；後面一定要加上反斜線 \ 銜接執行個體名稱)
* 驗證: SQL Server 驗證
* 帳號: sa 
(PS: sa 代表 System Administrator (系統管理員)，內建的資料庫最高權限帳號)
* 密碼: (填入 Windows 登入密碼)
* 加密: 設為 "選用"，並勾選 "信任伺服器憑證"

4. 點擊: "連接"


## Step-5. 建立資料前準備

### 5-1. 資料庫設計 - ERD (實體關聯圖)
![image](https://hackmd.io/_uploads/S1GoJXcnZx.png)

---

### 5-2. (Optional) 如果要用設計工具(UI)建立資料的話
至：工具 > 選項 > 設計師 > 資料表... > 取消勾選: "防止儲存..."

---

### 5-3. 執行順序總覽

| 檔案 | 說明 |
|------|------|
| `1_create_database.sql` | 刪除舊資料庫（若存在）並重建 |
| `2_create_table_roles.sql` | 建立 Roles 資料表 |
| `3_insert_table_roles.sql` | 插入 Roles 範例資料 |
| `4_create_table_users.sql` | 建立 Users 資料表 |
| `5_insert_table_users.sql` | 插入 Users 範例資料 |
| `6_create_table_devices.sql` | 建立 Devices 資料表 |
| `7_insert_table_devices.sql` | 插入 Devices 範例資料 |
| `8_create_table_roledevices.sql` | 建立 RoleDevices 資料表 |
| `9_insert_table_roledevices.sql` | 插入 RoleDevices 範例資料 |
| `10_set_all_foreign_keys.sql` | 建立所有外鍵約束 (FK) |

> ⚠️ **注意**：FK 必須最後設定，確保所有資料表與資料都已建立完成


---

### 5-4. ⚠️ 不可不知 ⚠️

Q: 建完資料表也按了重新整理 但打資料表名稱會有紅色波浪底線 為何
A: 
(1) 解法
快捷鍵 "Ctrl + Shift + R" 
或
編輯 (Edit) -> IntelliSense -> 重新整理本地快取 (Refresh Local Cache)

(2) 原因
因為 SQL Server Management Studio (SSMS) 的 IntelliSense（自動完成功能）快取還沒更新

即便你重新整理了左側的「物件總管」，SSMS 編輯視窗內部的語法檢查器（IntelliSense）可能還停留在舊的資料庫架構紀錄


---

## Step-6. 建立資料庫、建立資料表、插入資料

### 6-1. 刪除舊資料庫並重建

➡️ 開啟 SSMS，新增查詢，執行 `1_create_database.sql`

```sql
IF EXISTS (SELECT name FROM sys.databases WHERE name = 'DeviceMonitor')
BEGIN
    ALTER DATABASE DeviceMonitor SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    DROP DATABASE DeviceMonitor;
END
GO

CREATE DATABASE DeviceMonitor;
GO

USE DeviceMonitor;
GO
```

➡️ 執行後，左側物件總管 > 右鍵 **Databases** > **重新整理**，確認 `DeviceMonitor` 已出現


---

### 6-2. 建立 Roles 資料表

> 💡 **為何先建 Roles？** Users 的 `RoleId` 會參考 Roles，所以 Roles 必須先存在


➡️ 執行 `2_create_table_roles.sql`

```sql
USE DeviceMonitor;
GO

CREATE TABLE Roles (
    Id          INT IDENTITY(1,1) NOT NULL,
    [Name]      NVARCHAR(20)      NULL,
    CreatedDate DATETIME          NULL,
    UpdatedDate DATETIME          NULL,

    CONSTRAINT PK_Roles PRIMARY KEY (Id)
);
GO
```

---

### 6-3. 插入 Roles 範例資料

➡️ 執行 `3_insert_table_roles.sql`

```sql
USE DeviceMonitor;
GO

INSERT INTO Roles ([Name], CreatedDate, UpdatedDate)
VALUES 
(N'系統管理者', GETDATE(), GETDATE()),
(N'北區使用者', GETDATE(), GETDATE()),
(N'南區使用者', GETDATE(), GETDATE());
GO
```

➡️ 執行後可用以下語句確認結果：
```sql
SELECT * FROM DeviceMonitor.dbo.Roles;
```

| Id | Name | CreatedDate | UpdatedDate |
|----|------|-------------|-------------|
| 1 | 系統管理者 | ... | ... |
| 2 | 北區使用者 | ... | ... |
| 3 | 南區使用者 | ... | ... |

---

### 6-4. 建立 Users 資料表

➡️ 執行 `4_create_table_users.sql`

```sql
USE DeviceMonitor;
GO

CREATE TABLE Users (
    Id          INT IDENTITY(1,1) NOT NULL,
    Account     VARCHAR(50)       NULL,
    [Name]      NVARCHAR(50)      NULL,
    Email       VARCHAR(50)       NULL,
    Pwd         VARCHAR(200)      NULL,
    IsActive    BIT               NULL,
    RoleId      INT               NULL,
    CreatedDate DATETIME          NULL,
    UpdatedDate DATETIME          NULL,

    CONSTRAINT PK_Users PRIMARY KEY (Id)
);
GO
```

---

### 6-5. 插入 Users 範例資料

➡️ 執行 `5_insert_table_users.sql`

```sql
USE DeviceMonitor;
GO

INSERT INTO Users (Account, [Name], Email, Pwd, IsActive, RoleId, CreatedDate, UpdatedDate)
VALUES 
('admin',        N'系統管理員', 'admin@devicemonitor.com',   'hash_pwd_123456', 1, 1, GETDATE(), GETDATE()),
('jeff_chiang',  N'江小魚',     'jeff.c@example.com',        'hash_pwd_789012', 1, 2, GETDATE(), GETDATE()),
('mary_lee',     N'李瑪莉',     'mary.lee@test.com',         'hash_pwd_345678', 1, 2, GETDATE(), GETDATE()),
('guest_01',     N'訪客帳號',   'guest@temp.com',            'hash_pwd_abcdef', 0, 3, '2023-12-01 10:00:00', '2023-12-05 14:30:00'),
('tech_support', N'技術工程師', 'support@devicemonitor.com', 'hash_pwd_qwerty', 1, 2, GETDATE(), GETDATE());
GO
```

➡️ (Optional) 確認資料：`SELECT * FROM DeviceMonitor.dbo.Users;`

---

### 6-6. 建立 Devices 資料表

➡️ 執行 `6_create_table_devices.sql`

```sql
USE DeviceMonitor;
GO

CREATE TABLE Devices (
    Id          INT IDENTITY(1,1) NOT NULL,
    Code        VARCHAR(50)       NULL,
    [Name]      NVARCHAR(50)      NULL,
    DeviceType  VARCHAR(20)       NULL,
    Params      NVARCHAR(200)     NULL,
    Lat         DECIMAL(9,6)      NULL,
    Lng         DECIMAL(9,6)      NULL,
    IsActive    BIT               NULL,
    Status      VARCHAR(20)       NULL,
    CreatedDate DATETIME          NULL,
    UpdatedDate DATETIME          NULL,

    CONSTRAINT PK_Devices PRIMARY KEY (Id)
);
GO
```

---

### 6-7. 插入 Devices 範例資料

➡️ 執行 `7_insert_table_devices.sql`

```sql
USE DeviceMonitor;
GO

INSERT INTO Devices (Code, [Name], DeviceType, Params, Lat, Lng, IsActive, Status, CreatedDate, UpdatedDate)
VALUES
('CCTV-N001', N'國道1號北上001', 'camera', N'{"VideoStream":"rtsp://192.168.1.1/stream1"}', 25.066390, 121.623800, 1, 'active', '2025-02-01 00:00:00', '2025-02-01 00:00:00'),
('CCTV-N002', N'國道1號北上002', 'camera', N'{"VideoStream":"rtsp://192.168.1.2/stream1"}', 24.763533, 120.999000, 1, 'active', '2025-02-01 00:00:00', '2025-02-01 00:00:00'),
('CCTV-N003', N'國道3號北上001', 'camera', N'{"VideoStream":"rtsp://192.168.1.3/stream1"}', 25.006725, 121.574200, 1, 'active', '2025-02-01 00:00:00', '2025-02-01 00:00:00'),
('CCTV-N004', N'國道1號南下001', 'camera', N'{"VideoStream":"rtsp://192.168.1.4/stream1"}', 23.263935, 120.260900, 1, 'active', '2025-02-01 00:00:00', '2025-02-01 00:00:00'),
('CCTV-N005', N'國道1號南下002', 'camera', N'{"VideoStream":"rtsp://192.168.1.5/stream1"}', 22.689950, 120.357000, 1, 'active', '2025-02-01 00:00:00', '2025-02-01 00:00:00');
GO
```

---

### 6-8. 建立 RoleDevices 資料表

> 💡 **用途**：這是 Roles 和 Devices 的「多對多」中介表，記錄哪個角色可以存取哪些裝置


➡️ 執行 `8_create_table_roledevices.sql`

```sql
USE DeviceMonitor;
GO

CREATE TABLE RoleDevices (
    Id       INT IDENTITY(1,1) NOT NULL,
    RoleId   INT               NULL,
    DeviceId INT               NULL,

    CONSTRAINT PK_RoleDevices PRIMARY KEY (Id)
);
GO
```

---

### 6-9. 插入 RoleDevices 範例資料

➡️ 執行 `9_insert_table_roledevices.sql`

```sql
USE DeviceMonitor;
GO

INSERT INTO RoleDevices (RoleId, DeviceId)
VALUES
(1, 1),
(1, 2),
(1, 3),
(1, 4),
(1, 5);
GO
```

➡️ 此範例代表「系統管理者 (RoleId=1)」可存取全部 5 台裝置

---

### 6-10. 建立所有外鍵約束 (Foreign Keys)

> ⚠️ **此步驟必須最後執行**，確保所有資料表與資料都已建立完成


➡️ 執行 `10_set_all_foreign_keys.sql`

```sql
USE DeviceMonitor;
GO

-- FK 1: Users.RoleId -> Roles.Id
ALTER TABLE Users
ADD CONSTRAINT FK_Users_Roles
    FOREIGN KEY (RoleId) REFERENCES Roles(Id);
GO

-- FK 2: RoleDevices.RoleId -> Roles.Id
ALTER TABLE RoleDevices
ADD CONSTRAINT FK_RoleDevices_Roles
    FOREIGN KEY (RoleId) REFERENCES Roles(Id);
GO

-- FK 3: RoleDevices.DeviceId -> Devices.Id
ALTER TABLE RoleDevices
ADD CONSTRAINT FK_RoleDevices_Devices
    FOREIGN KEY (DeviceId) REFERENCES Devices(Id);
GO
```

➡️ 執行後重新整理，在各資料表的 **Keys** 節點下應可看到：
- `Users` > Keys > `FK_Users_Roles`
- `RoleDevices` > Keys > `FK_RoleDevices_Roles`、`FK_RoleDevices_Devices`

---

### 6-11. 補充：為何 FK 要最後建立？

建立 FK 時，資料庫會立即驗證**現有資料的參照完整性**
若先設 FK 再插入資料，插入順序不對就會報錯
例如：
- 先建 `FK_Users_Roles` 再插入 Users 資料 → 插入時 Roles 必須已有對應資料，否則報錯
- **最安全的做法**：建完所有表 → 插完所有資料 → 最後統一加 FK

---

### 6-12. 補充：若無加上外鍵約束會如何？
**1. 孤兒資料 (Orphaned Data)**
刪除 Roles 中某個角色後，Users 中仍有 `RoleId` 指向已不存在的角色，JOIN 查詢時會找不到角色名稱，導致顯示錯誤甚至程式崩潰

**2. 無效的關聯 (Invalid References)**
沒有約束時，可以隨意將 Users 的 `RoleId` 設為 999，即使 Roles 表中根本沒有 Id=999 的資料，資料庫也不會攔截

**3. 必須靠程式碼手動檢查**
後端程式（C# / Java）需要撰寫大量額外判斷邏輯，且若有多個系統同時操作同一資料庫，只要任一系統沒寫好，資料就會出錯

---

### ref 
[SQL Server資料庫設計教學](https://youtu.be/19TsIFHaEec?si=GiVEibPv1qULfjDR)
