首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

SQL Server 變數賦值大不同:SET vs SELECT 深度對比與最佳實踐

     編輯:MySQL 資料庫相關知識

為什麼同樣賦值,卻有兩種寫法?

在 T-SQL 中,`SET` 和 `SELECT` 都能給變數賦值,但行為差異顯著。誤用可能導致邏輯錯誤、效能損耗甚至難以除錯。本文透過四大核心場景實測對比,建立正確選擇準則。

測試環境準備

DECLARE @VAR1 VARCHAR(10), @VAR2 VARCHAR(10);

差異 1:多變數同時賦值

寫法語法執行計畫/網路往返
SELECTSELECT @VAR1='Y', @VAR2='N';單一陳述式,單次編譯/執行
SETSET @VAR1='Y'; SET @VAR2='N';兩個獨立陳述式,雙倍開銷

結論: 批次賦值優先用 SELECT,減少網路往返與編譯開銷。

差異 2:子查詢回傳多筆資料

-- 假設 Permission 表有多筆 IsRight
SELECT @VAR1 = IsRight FROM Permission;  -- ✅ 成功,取最後一筆 (非確定性)
SET @VAR1 = IsRight FROM Permission;     -- ❌ 錯誤:Subquery returns more than 1 value

結論: 不確定筆數時,SET 會拋錯保護資料正確性;SELECT 靜默取最後一筆,極易產生隱性 Bug。嚴謹場景請用 SET。

差異 3:子查詢回傳零筆 (NULL 結果)

-- 假設 Permission 表為空
SET @VAR1 = '初始值';
SELECT @VAR1 = IsRight FROM Permission;       -- @VAR1 保持 '初始值' (不變更)
SET @VAR1 = (SELECT IsRight FROM Permission); -- @VAR1 變為 NULL

關鍵差異:

  • SELECT 直接賦值:查無資料時不修改變數,保留原值。
  • SET 標量子查詢:查無資料回傳 NULL,強制變數歸 NULL。

實務陷阱: 若後續邏輯依賴「變數是否被賦值」,SELECT 行為極危險!建議先初始化再用 SET,或顯式判斷 `@@ROWCOUNT`。

差異 4:標量子查詢無資料時 (兩者一致)

SET @VAR1 = '初始值';
SELECT @VAR1 = (SELECT IsRight FROM Permission); -- @VAR1 = NULL
SET @VAR1 = (SELECT IsRight FROM Permission);    -- @VAR1 = NULL

當使用標量子查詢語法 `(SELECT ...)` 時,SELECT 與 SET 行為一致:無資料 → NULL。

特殊內建變數:@@ERROR 與 @@ROWCOUNT

這兩個系統函數語句級重置,必須在同一陳述式捕獲:

-- ❌ 錯誤:分兩句 SET,@@ROWCOUNT 已被重置
SET @Err = @@ERROR;
SET @Rows = @@ROWCOUNT;

-- ✅ 正確:SELECT 同句捕獲
SELECT @Err = @@ERROR, @Rows = @@ROWCOUNT;

選擇決策樹

需要同時賦值多個變數? → SELECT

賦值來源為單一標量子查詢? → SET (ANSI 標準、可讀性佳、錯誤語意清晰)

賦值來源為直接查詢表/視圖 (可能多筆/零筆)? → SET (強制單一值語意) + 顯式 `TOP 1` / `MAX()` 確保確定性

需捕獲 @@ERROR/@@ROWCOUNT? → SELECT

一般純量常數賦值? → SET (標準、意圖明確)

最佳實踐總結

  1. 預設用 SET:符合 ANSI SQL 標準,語意明確「單一值賦值」,編譯器能檢查多值錯誤。
  2. 批次賦值、捕獲系統函數用 SELECT:效能與功能必要性。
  3. 絕不依賴 SELECT「查無資料不改變」特性:寫法隱晦,維護者極易誤解。改用 `IF EXISTS` 或 `SET @v = (SELECT ...)` 明確語意。
  4. 子查詢加 TOP 1 / 聚合函數:確保確定性,避免「取最後一筆」的非確定性行為。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved