owned this note
owned this note
Published
Linked with GitHub
# C# with SQL server
[SQL筆記](/Yvu8r41uQveze80lKLJvWQ)有一些相關語法、概念可供了解
(如果有需要下載SQL sever 這裡有教學可以看 https://ithelp.ithome.com.tw/m/articles/10235779
**目錄:**
[TOC]
## 新增資料

在這即可輸入你要的行列,每行的名稱以及類型「ID,int,不允許Null」

記得要儲存以及重跑一下資料庫,就可以看到加入的資料

選取前1000、200資料列都可以手動加入資料

## 建立資料庫
也可以使用新增查詢使用程式語言來新增資料庫
```sql=
CREATE DATABASE MyDatabase;
```
### 使用資料庫
```sql=
USE MyDatabase;
```
## 建立資料表
```sql=
CREATE TABLE Users (
UserID INT PRIMARY KEY IDENTITY(1,1), -- 自增主鍵
UserName NVARCHAR(50) NOT NULL, -- 使用 NVARCHAR 支援 Unicode
Age INT CHECK (Age >= 0), -- 年齡必須大於等於 0
Email NVARCHAR(100) UNIQUE, -- Email 欄位唯一
CreatedAt DATETIME DEFAULT GETDATE() -- 預設值為當前時間
);
```
## 連結資料
目前看來,我常與C#進行連結,這其中大概就只有那一長串的不一樣了
以下幾種都可以連結到的
在 SSMS 內,打開 「連線屬性」 (右鍵資料庫 → 屬性 → 連線 ),可以找到伺服器名稱。
* Windows 驗證:後面為=True;
* SQL Server 驗證:其中會有User Id=****;Password=****或者底部為.mdf;如此
範例:
```csharp=
// 使用 Windows 驗證(Trusted Connection)
string connectionString = "Server=你的伺服器名稱;Database=你的資料庫名稱;Trusted_Connection=True;";
// 使用 SQL Server 驗證(需要帳號密碼)
string connectionString = "Server=你的伺服器名稱;Database=你的資料庫名稱;User Id=你的帳號;Password=你的密碼;";
```
### C#連結測試
```csharp=
string connectionString = "Server=localhost\SQLEXPRESS;Database=master;Trusted_Connection=True;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
try
{
conn.Open();
MessageBox.Show("✅ 成功連接到 SQL Server!");
}
catch (Exception ex)
{
MessageBox.Show($"❌ 連線失敗:{ex.Message}");
}
}
```
## 獲取 SQL 語法
1. 開啟 SQL Server Management Studio (SSMS),並連接到你的 SQL Server。
1. 在 「物件總管」(Object Explorer) 中,找到你的 資料庫 (Database),然後展開它。
1. 在 「資料表 (Tables)」 裡找到你要查詢的表,例如 test3。
1. 右鍵點擊資料表,選擇 「Script Table as」,然後選擇你需要的 SQL 語法:
* SELECT To → 產生 SELECT 查詢語法
* INSERT To → 產生 INSERT INTO 語法
* UPDATE To → 產生 UPDATE 語法
* DELETE To → 產生 DELETE 語法
5. 選擇 To New Query Editor Window,SSMS 會自動開啟一個新視窗,並顯示對應的 SQL 語法。

我建議第一個用到 新增查詢編輯器視窗 ,剩下的用到 剪貼簿 ,用貼上的發法集中在一個 查詢編輯器視窗
1. CREATE : 這個指令用於創建新的資料庫物件,例如表格、索引、視圖等。
2. ALTER : 這個指令用於修改現有的資料庫物件,例如增加/刪除欄位、變更資料類型等。
1. 建立或改變為: 這個指令看起來是用於同時創建和修改資料庫物件,可能是一個複合指令。
1. DROP : 這個指令用於刪除資料庫物件,例如刪除表格、索引等。
1. DROP 並 CREATE : 這個指令看起來是先刪除再創建資料庫物件,可能是一個原子操作。
2. SELECT : 這是SQL中最常用的查詢指令,用於從數據表中選取和返回數據。它可以指定要查詢的列、過濾條件、排序方式等。
1. INSERT : 這個指令用於向數據表中插入新的記錄。可以指定要插入的列和值。
1. UPDATE : 這個指令用於更新數據表中現有的記錄。可以指定要更新的列和新的值,並添加過濾條件。
1. DELETE : 這個指令用於從數據表中刪除記錄。可以指定要刪除的記錄的過濾條件。
3. EXECUTE : 這個指令用於執行一個SQL語句或存儲過程。
### 範例
假設你選擇 INSERT To,SSMS 可能會產生:
```sql=
INSERT INTO [dbo].[test3] ([ID], [Name], [Age])
VALUES (<ID, int,>, <Name, nvarchar(50),>, <Age, int,>)
```
你可以根據需求修改,例如:
```sql=
INSERT INTO [dbo].[test3] ([ID], [Name], [Age])
VALUES (1, 'Anna', 25)
```
# C#編寫建議
### 使用 SqlCommand 執行 SQL
建議使用 參數化查詢
```csharp=
string query = "INSERT INTO test3 (ID, Name, Age) VALUES (@id, @name, @age)";
using (SqlConnection conn = new SqlConnection("你的連線字串"))
{
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("@id", 1);
cmd.Parameters.AddWithValue("@name", "Anna");
cmd.Parameters.AddWithValue("@age", 25);
conn.Open();
cmd.ExecuteNonQuery();
}
```
### 注入攻擊
❌❌ 傳統寫法 (⚠️ 不安全)
這樣的寫法 直接將變數串接進 SQL 指令,容易受到 SQL Injection (SQL 注入攻擊) 的影響
SQL Injection:是發生於應用程式與資料庫層的安全漏洞
在設計不良的程式當中忽略了字元檢查,那麼這些夾帶進去的惡意指令就會被資料庫伺服器誤認為是正常的SQL指令而執行,因此遭到破壞或是入侵。
```csharp
string query = "INSERT INTO test3 (ID, Name, Age) VALUES (" + id + ", '" + name + "', " + age + ")";
```
### 多行sql語法(reader開啟關閉)
reader有開啟(Open)就有關閉(Close)
```csharp=
//取得ID
string query = @"
SELECT [ID]
FROM [dbo].[Account]
WHERE [Username] = @Username AND [HashPassword] = @HashPassword";
using (SqlConnection conn = new SqlConnection(conn_string))
{
using (SqlCommand cmd = new SqlCommand(query, conn))
{
//寫入帳號密碼,這種方法有效避免sql注入風險
cmd.Parameters.AddWithValue("@Username", textBox1.Text);
cmd.Parameters.AddWithValue("@HashPassword", textBox2.Text);
conn.Open(); //資料庫開啟
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (!reader.Read()) //讀取失敗
{
MessageBox.Show("帳號或密碼錯誤");
return;
}
//儲存帳號資訊
string id = reader["ID"].ToString();
// 關閉 reader 後執行 UPDATE
reader.Close();
//////////////////////////////////////////////////////////////////////////
//更新登陸時間
string updateQuery = @"
UPDATE [dbo].[Account]
SET [LastUpdatedTime] = @LastUpdatedTime
WHERE [ID] = @ID";
using (SqlCommand updateCmd = new SqlCommand(updateQuery, conn))
{
updateCmd.Parameters.AddWithValue("@ID", id);
updateCmd.Parameters.AddWithValue("@LastUpdatedTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz"));
updateCmd.ExecuteNonQuery();
}
}
}
}
```
如果要做兩個資料庫的動作,害怕**名子混在一起**,可以進行分開查詢:
```csharp=
string accountId = "";
string vehicleId = "";
using (SqlConnection conn = new SqlConnection(conn_string))
{
conn.Open();
// 查帳號 ID
string query1 = "SELECT [ID] FROM [dbo].[Account] WHERE [Email] = @Email";
using (SqlCommand cmd1 = new SqlCommand(query1, conn))
{
cmd1.Parameters.AddWithValue("@Email", email);
using (SqlDataReader reader = cmd1.ExecuteReader())
{
if (reader.Read())
{
accountId = reader["ID"].ToString(); // 這裡的 reader["ID"] 是帳號的 ID
}
}
}
// 查車輛 ID
string query2 = "SELECT [ID] FROM [dbo].[Vehicle] WHERE [AccountID] = @AccountID";
using (SqlCommand cmd2 = new SqlCommand(query2, conn))
{
cmd2.Parameters.AddWithValue("@AccountID", accountId);
using (SqlDataReader reader = cmd2.ExecuteReader())
{
if (reader.Read())
{
vehicleId = reader["ID"].ToString(); // 這裡的 reader["ID"] 是車輛的 ID
}
}
}
}
```
如果一個sql語言中有多個表單資料:
就需要用AS特別標註
```sql=
SELECT
V.ID AS VehicleID,
V.PlateNumber,
A.ID AS AccountID,
A.Email,
AWV.ID AS LinkID
FROM Vehicle V --省略AS
JOIN AccountWithVehicle AWV ON V.ID = AWV.VehicleID
JOIN Account A ON AWV.AccountID = A.ID
```
```csharp=
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
string vehicleId = reader["VehicleID"].ToString();
string plate = reader["PlateNumber"].ToString();
string accountId = reader["AccountID"].ToString();
string email = reader["Email"].ToString();
string linkId = reader["LinkID"].ToString();
}
}
```
總結:
| 原因 | 說明 |
| ---------------------------------------------- | -------------- |
| 每個查詢用不同 `SqlCommand` 變數(如 `cmd1`、`cmd2`) | 避免 query 與參數混用 |
| 每個讀取用不同 `SqlDataReader`(如 `reader1`、`reader2`) | 分清楚是哪張資料表的結果 |
| 儲存資料用不同變數(如 `accountId`、`vehicleId`) | 確保內容不會覆蓋或混淆 |
| 只開一次連線 (`conn.Open()`) | 避免重複開啟導致錯誤 |
---
💡💡記得最後的最後都要加上
```csharp=
conn.Open();
cmd.ExecuteNonQuery(); //是非同步非查詢作業(例如 INSERT/UPDATE/DELETE)。
cmd.ExecuteReader() //是同步查詢作業。
```
如果要查詢資料庫,請勿加 **ExecuteNonQuery()**
不能「先開始一個非同步操作」然後又「同步查詢資料」!
```csharp=
using(SqlDataReader reader = comm.ExecuteReader())
//會報錯:不可因為已在進行的非同步作業擱置而先執行命令。
```
⚠️如果結束一段SQL語法後還要接一段,記得加上 reader.Close()
SqlCommand 也是得再宣告一個使用
```csharp=
reader.Close(); // 先關閉 reader,避免與 UPDATE 衝突
string query = ...;
using (SqlCommand updateCmd = new SqlCommand(updateQuery, conn)){...}
```
----
讀取資料後可進行的編輯方式:
```csharp=
using(var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
FirstName = reader["FirstName"].ToString();
LastName = reader["LastName"].ToString();
.....
}
}
```
### 寫空的語法
✅ 這句:
```sql=
(@EngineType IS NULL OR BM.EngineType = @EngineType
```
意思是:
如果 `@EngineType` 是 `NULL`(代表「未指定」或「全部」),那就不要套用這個篩選條件。
否則就要符合指定的 `EngineType`。
👉 適合用於參數類型為 **數值(int) 或 可為 NULL 的欄位**。
✅ 這句:
```sql=
(@BrandCode = '' OR BM.Code = @BrandCode)
```
意思是:
如果 @`BrandCode` 是空字串 `''`(代表「全部」),那就不要篩選品牌代號。
否則就必須等於指定的 `BrandCode`。
👉 適合用於**參數類型為 字串(string)**,例如品牌代號 Code 是 varchar。
⚖️ 差異總結
| 比較項目 | `IS NULL` 用法 | `= ''` 用法 |
| --------- | ---------------------------------------------------- | ------------------------------------------ |
| 適用型別 | `int`, `datetime`, `bit` 等 | `nvarchar`, `varchar` 等字串類型 |
| 預設值表示「全部」 | `null` | 空字串 `""` |
| C#參數要怎麼設 | `command.Parameters.AddWithValue(..., DBNull.Value)` | `command.Parameters.AddWithValue(..., "")` |
| SQL 可讀性 | 適合數值與空日期 | 適合純文字比較 |
🧠 小技巧建議你這樣記:
| 條件型別 | 要排除的「全部」值 | SQL條件語法 |
| ------- | ------------- | ------------------------- |
| 數字或可空欄位 | `null` | `(@值 IS NULL OR 欄位 = @值)` |
| 字串欄位 | `""` 或 `'全部'` | `(@值 = '' OR 欄位 = @值)` |
## SELECT 查詢資料
```sql=
SELECT 欄位1, 欄位2, ...
FROM 資料表名稱
WHERE 條件;
```
```csharp=
using System;
using System.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString = "Server=你的伺服器名稱;Database=你的資料庫名稱;Trusted_Connection=True;";
string query = "SELECT ID, Name, Age FROM test3";
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read()) //搜尋每一筆資料
{
//在這裡加入條件就可以輸出所有符合條件的資料
Console.WriteLine($"ID: {reader["ID"]}, Name: {reader["Name"]}, Age: {reader["Age"]}");
}
}
}
}
}
```
判斷資料存在 以及 存取單筆資料庫資料
```csharp=
if (reader.Read()) // 帳戶存在
{
int accountStatus = Convert.ToInt32(reader["AccountStatus"]);
string firstName = reader["FirstName"].ToString();
// **檢查帳戶狀態**
if (accountStatus == 2)
{
MessageBox.Show("帳戶已被鎖定,無法登入", "警告");
return;
}
}
```
🔹 ExecuteReader():用於查詢 (SELECT) 並回傳多筆資料。
### 查詢所有資料( * )
```sql
SELECT * FROM Users;
```
### 只查詢 UserName 和 Password
```sql
SELECT UserName, Password FROM Users;
```
### 查詢特定使用者 WHERE
```sql
SELECT * FROM Users WHERE UserName = 'Anna';
```
### 查詢多種條件 (AND、OR)
📌 AND 與 OR 的區別
AND:兩個條件都必須滿足,才會返回結果。
OR:只要其中一個條件成立,就會返回結果。
普通時候可以加括號。AND 和 OR 混用,就需要加括號
```sql
SELECT * FROM Users WHERE UserName = 'Anna' AND Password = '12345';
```
(在 while 底下使用判斷式來塞選,才可以列出所有相關資料)
* 查詢 Id 大於 1 的使用者
```sql
SELECT * FROM Users WHERE Id > 1;
```
### 最後一筆資料(最大 Id 的資料)ORDER BY
🔹SELECT TOP 1 *:取 最上面 1 筆資料
排序方式 | SQL 語法 | Entity Framework 語法 | 結果
----------------------|------------------------|-------------------------------|----------------
升序(順序排列) | ORDER BY Id ASC | OrderBy(u => u.Id) | Id 小 → 大
降序(最新資料在前) | ORDER BY Id DESC | OrderByDescending(u => u.Id) | Id 大 → 小
```sql
SELECT TOP 1 * FROM Users ORDER BY Id DESC
```
* 獲取 最後插入的 Id
IDENT_CURRENT('Users') 會回傳 最後一筆 Id,不受 SESSION 限制
```sql
SELECT IDENT_CURRENT('Users')
```
### EXISTS 資料有無存在(最佳方法)
```csharp=
string query = "SELECT CASE WHEN EXISTS (SELECT 1 FROM Users WHERE UserName = @UserName) THEN 1 ELSE 0 END";
using (SqlCommand cmd = new SqlCommand(query, conn))
{
cmd.Parameters.AddWithValue("@UserName", userNameToCheck);
int exists = (int)cmd.ExecuteScalar(); // 執行查詢並取得結果
if (exists == 1)
Console.WriteLine("資料存在");
else
Console.WriteLine("資料不存在");
}
```
📌 優點:
✅ EXISTS 會在找到符合條件的第一筆資料後就停止,不會繼續搜尋,效能較好。
✅ 適合用於 條件判斷(例如 IF、CASE)。
### COUNT(*) 資料有無存在
```csharp=
string query = "SELECT COUNT(*) FROM Users WHERE UserName = @UserName";
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("@UserName", "Anna");
int count = (int)cmd.ExecuteScalar();
if (count > 0)
Console.WriteLine("資料存在");
else
Console.WriteLine("資料不存在");
```
📌 回傳值:
* 0:代表資料 不存在
* 1 或以上:代表資料 存在 (也可以查看多少資料在內ouo
📌 優點:
✅ 可計算符合條件的筆數,適合用來檢查 多筆記錄 是否存在。
📌 缺點:
❌ 即使找到第一筆,仍然會繼續搜尋,可能影響效能。
### 輸出所有符合條件的資料
除了在輸出的時候加上if條件來寫法:
```csharp=
string SELECT = "SELECT [Id], [User], [Password] FROM [dbo].[Table_1];";
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand comm = new SqlCommand(SELECT, conn);
conn.Open();
using (SqlDataReader reader = comm.ExecuteReader())
{
dataGridView1.Rows.Clear();
while (reader.Read())
{
if ((reader["Id"]).ToString() == textBox1.Text || (reader["User"]).ToString() == textBox2.Text || (reader["Password"]).ToString() == textBox3.Text) //是不是有更好的方法輸出所有符合條件的資料
{
dataGridView1.Rows.Add(reader["Id"], reader["User"], reader["Password"]);
}
}
}
}
```
還可以使用:
加快速度~
```csharp=
string SELECT = "SELECT [Id], [User], [Password] FROM [dbo].[Table_1] WHERE ([Id] = @id OR @id IS NULL) AND ([User] = @user OR @user IS NULL) AND ([Password] = @password OR @password IS NULL)";
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand comm = new SqlCommand(SELECT, conn);
// 使用參數化查詢來防止SQL注入
comm.Parameters.AddWithValue("@id", string.IsNullOrEmpty(textBox1.Text) ? (object)DBNull.Value : textBox1.Text);
comm.Parameters.AddWithValue("@user", string.IsNullOrEmpty(textBox2.Text) ? (object)DBNull.Value : textBox2.Text);
comm.Parameters.AddWithValue("@password", string.IsNullOrEmpty(textBox3.Text) ? (object)DBNull.Value : textBox3.Text);
conn.Open();
using (SqlDataReader reader = comm.ExecuteReader())
{
dataGridView1.Rows.Clear();
while (reader.Read())
{
dataGridView1.Rows.Add(reader["Id"], reader["User"], reader["Password"]);
}
}
}
```
## INSERT 新增資料
```csharp=
using System;
using System.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString = "Server=你的伺服器名稱;Database=你的資料庫名稱;Trusted_Connection=True;";
string query = "INSERT INTO test3 (ID, Name, Age) VALUES (@id, @name, @age)";
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("@id", 2);
cmd.Parameters.AddWithValue("@name", "Bob");
cmd.Parameters.AddWithValue("@age", 30);
conn.Open();
int rowsAffected = cmd.ExecuteNonQuery();
Console.WriteLine($"成功新增 {rowsAffected} 筆資料");
}
}
}
```
🔹 ExecuteNonQuery():用於執行 INSERT、UPDATE、DELETE,回傳影響的資料筆數。
### 小小總結
用途 | SQL 語法 | C# (ADO.NET) | C# (Entity Framework)
------------------|-------------------------------------------------|-------------------------------------------|-------------------------------------------
新增單筆資料 | INSERT INTO Users (User, Password) VALUES ('Anna', '123456'); | 使用 cmd.ExecuteNonQuery(); | db.Users.Add(user); db.SaveChanges();
新增多筆資料 | INSERT INTO Users (User, Password) VALUES ('A', '1'), ('B', '2'); | 需使用迴圈插入 | 需使用迴圈插入
取得 Id | OUTPUT INSERTED.Id | (int)cmd.ExecuteScalar(); | db.Users.Add(user); db.SaveChanges(); user.Id;
## UPDATE 更新資料(修改)
```csharp=
string query = "UPDATE test3 SET Name = @name WHERE ID = @id";
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("@name", "Charlie");
cmd.Parameters.AddWithValue("@id", 2);
conn.Open();
int rowsAffected = cmd.ExecuteNonQuery();
Console.WriteLine($"成功更新 {rowsAffected} 筆資料");
}
```
### 語法說明
條件與想改變的資料可為同一欄 ( 將 Password 為 '123' 的使用者,更新為 '54321' )
```sql=
UPDATE 資料表名稱
SET 欄位1 = 值1, 欄位2 = 值2, ...
WHERE 條件;
```
* 範例
有一個Anna資料在Id-1,想改變Password 成 '54321'
💡舊的資料:
| Id | UserName | Password |
|----|----------|----------|
| 1 | Anna | 12345 |
| 2 | Bob | 67890 |
```sql=
UPDATE Users
SET Password = '54321'
WHERE Id = 1;
```
💡新的資料:
| Id | UserName | Password |
|----|----------|----------|
| 1 | Anna | 54321 |
| 2 | Bob | 67890 |
## DELETE 刪除資料
```csharp=
string query = "DELETE FROM test3 WHERE ID = @id";
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("@id", 2);
conn.Open();
int rowsAffected = cmd.ExecuteNonQuery();
Console.WriteLine($"成功刪除 {rowsAffected} 筆資料");
}
```
### 刪除所有資料
```sql
DELETE FROM Users
```
### 刪除整個表 (結構+資料)
```sql
DROP TABLE Users
```
### 刪除指定的那一行
刪除與該 Id 同一行的 Name 和 Password
不影響其他相同 Name 和 Password 的行
```sql
DELETE FROM Users WHERE Id = @Id
AND Name = (SELECT Name FROM Users WHERE Id = @Id)
AND Password = (SELECT Password FROM Users WHERE Id = @Id);
```
## SqlConnection
📌 SqlConnection 主要用途
* 建立與 SQL Server 資料庫的連線
* 執行 SQL 查詢(SELECT、INSERT、UPDATE、DELETE)
* 管理資料庫連線的開啟 (Open()) 和關閉 (Close())
Dispose() 釋放 SqlConnection 佔用的資源
State 取得當前連線狀態("Open"、"Closed" 等)
* 配合 SqlCommand 來執行 SQL 語句
* 與 SqlDataReader 或 SqlDataAdapter 搭配讀取資料
## SqlCommand
需要注意的地方
✅ 使用 using 確保自動釋放資源
✅ 使用參數化查詢 (@參數) 避免 SQL Injection
✅ 確保 SqlConnection 連線字串正確,否則會無法連線
✅ 如果 SQL Server 使用帳密登入,需要加上 User ID 和 Password
📌SqlCommand 是 C# 用來執行 SQL 指令 的物件,通常與 SqlConnection 搭配使用,能夠執行:
* 查詢 (SELECT) → 取得資料
* 新增 (INSERT)、修改 (UPDATE)、刪除 (DELETE) → 操作資料
* 執行儲存程序 (Stored Procedure)
* 執行資料庫指令 (ALTER TABLE, CREATE TABLE...等)
### 小小總結
* SqlCommand 用來執行 SQL 指令
* ExecuteReader():執行 SELECT,回傳 SqlDataReader
* ExecuteNonQuery():執行 INSERT, UPDATE, DELETE,回傳影響的資料筆數
* ExecuteScalar():執行 COUNT(*) 或單一數值查詢
* 可搭配參數 (@參數) 避免 SQL Injection
* 可執行儲存程序 (Stored Procedure)
| 方法 | 作用 |
|----------------------|--------------------------------------------|
| ExecuteReader() | 回傳查詢結果 (SELECT),用 SqlDataReader 讀取 |
| ExecuteNonQuery() | 執行 INSERT、UPDATE、DELETE,回傳影響的資料筆數 |
| ExecuteScalar() | 回傳單一值(例如 COUNT(*)) |
## SqlDataReader
SqlDataReader 是 C# 與 SQL Server 之間的資料讀取工具,專門用來 逐行讀取 SQL 查詢結果,適用於大量資料的高效讀取。
### 特性
1. 只能前向讀取(Forward-Only) 📜
不能回頭,只能逐行往下讀。
2. 串流讀取(Streaming) 🚀
不會一次載入所有資料到記憶體,適合處理大量資料。
3. 唯讀(Read-Only) 🔒
不能修改資料,只能讀取。
4. 效能較快 🏎️
因為是串流讀取,比 DataSet、DataTable 省記憶體。
### 注意事項
* reader.Read() 回傳 true 表示還有資料可以讀取,會移動到下一行。
* 資料類型要匹配,例如 GetInt32(0) 代表該欄位應該是 int。
* 欄位索引從 0 開始(第一欄是 0,第二欄是 1,依此類推)。
### 使用時機
✅ 當你只需要讀取資料,而且不會修改。
✅ 當資料量大時,避免一次載入全部到記憶體。
✅ 當需要即時顯示資料,如讀取資料時同時寫入畫面。
### 與DataTable 或 DataSet差別
如果需要修改、排序、篩選,請使用 DataTable 或 DataSet。
| 項目 | SqlDataReader | DataTable / DataSet |
|--------------|-----------------------------|-------------------------------|
| 適用場景 | 大量資料讀取(只讀) | 需要修改、過濾、排序 |
| 效能 | 較快(逐行讀取) | 較慢(會載入全部資料) |
| 記憶體使用 | 低(只存當前行) | 高(全部載入) |
| 移動方式 | 只能往下讀 | 可隨意跳行 |
# 資料匯出匯入
這個老師整理得很好!!
[SQL Server資料匯入與匯出](https://www.youtube.com/watch?v=C2jEhvT0ha8&ab_channel=%E8%AC%9D%E9%82%A6%E6%98%8C)

# 作者書寫測試檔案
存於github,壓縮檔案類型[sql_test](https://github.com/Anna0212Anna0212/sql_test)
C#檔案直接推送檔案[sql_test2.0](https://github.com/Anna0212Anna0212/sql_test2.0)
資料庫檔案都做成了Excel在檔案當中可做參考