在 T-SQL 中,`SET` 和 `SELECT` 都能給變數賦值,但行為差異顯著。誤用可能導致邏輯錯誤、效能損耗甚至難以除錯。本文透過四大核心場景實測對比,建立正確選擇準則。
DECLARE @VAR1 VARCHAR(10), @VAR2 VARCHAR(10);
| 寫法 | 語法 | 執行計畫/網路往返 |
|---|---|---|
| SELECT | SELECT @VAR1='Y', @VAR2='N'; | 單一陳述式,單次編譯/執行 |
| SET | SET @VAR1='Y'; SET @VAR2='N'; | 兩個獨立陳述式,雙倍開銷 |
結論: 批次賦值優先用 SELECT,減少網路往返與編譯開銷。
-- 假設 Permission 表有多筆 IsRight
SELECT @VAR1 = IsRight FROM Permission; -- ✅ 成功,取最後一筆 (非確定性)
SET @VAR1 = IsRight FROM Permission; -- ❌ 錯誤:Subquery returns more than 1 value
結論: 不確定筆數時,SET 會拋錯保護資料正確性;SELECT 靜默取最後一筆,極易產生隱性 Bug。嚴謹場景請用 SET。
-- 假設 Permission 表為空
SET @VAR1 = '初始值';
SELECT @VAR1 = IsRight FROM Permission; -- @VAR1 保持 '初始值' (不變更)
SET @VAR1 = (SELECT IsRight FROM Permission); -- @VAR1 變為 NULL
關鍵差異:
實務陷阱: 若後續邏輯依賴「變數是否被賦值」,SELECT 行為極危險!建議先初始化再用 SET,或顯式判斷 `@@ROWCOUNT`。
SET @VAR1 = '初始值';
SELECT @VAR1 = (SELECT IsRight FROM Permission); -- @VAR1 = NULL
SET @VAR1 = (SELECT IsRight FROM Permission); -- @VAR1 = NULL
當使用標量子查詢語法 `(SELECT ...)` 時,SELECT 與 SET 行為一致:無資料 → NULL。
這兩個系統函數語句級重置,必須在同一陳述式捕獲:
-- ❌ 錯誤:分兩句 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 (標準、意圖明確)