## [.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)