首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

T-SQL 控制流程陳述式完整指南:IF/ELSE、WHILE、GOTO、WAITFOR、TRY/CATCH、CASE 表達式

     編輯:關於SqlServer

前言

T-SQL 提供完整的程式控制流程結構,支援條件分支、迴圈、跳轉、等待、錯誤處理與條件運算。本文系統整理各陳述式語法、範例與避坑指南。

一、IF ... ELSE 條件分支


IF @Score >= 60
    PRINT N'及格';
ELSE
    PRINT N'不及格';

-- 多陳述式需用 BEGIN...END 區塊
IF @Score >= 90
BEGIN
    PRINT N'優等';
    INSERT INTO HonorRoll (StudentId) VALUES (@StudentId);
END
ELSE IF @Score >= 60
    PRINT N'及格';
ELSE
    PRINT N'不及格';
  • 條件必須為布林運算式 (回傳 TRUE/FALSE/UNKNOWN)。
  • UNKNOWN (含 NULL 比較) 視同 FALSE,進入 ELSE 區塊。

二、WHILE 迴圈


DECLARE @i INT = 1;
WHILE @i <= 10
BEGIN
    PRINT @i;
    SET @i += 1;
    
    -- 提前跳出
    IF @i = 5 BREAK;
    -- 跳過本次迴圈
    IF @i = 3 CONTINUE;
END
  • 條件為 TRUE 時持續執行;FALSE 或 UNKNOWN 結束。
  • BREAK 跳出迴圈;CONTINUE 跳至下一次迭代判斷。
  • **避免無限迴圈**:確保迴圈內修改條件變數。

三、GOTO 無條件跳轉


DECLARE @Retry INT = 0;
RetryLabel:
SET @Retry += 1;
IF @Retry > 3 GOTO ExitLabel;

-- 業務邏輯...
IF @@ERROR <> 0 GOTO RetryLabel;

ExitLabel:
PRINT N'結束';
  • 標籤格式:LabelName: (冒號結尾)。
  • **慎用**:破壞結構化程式設計,難以維護;優先考慮 WHILE/TRY-CATCH 替代。
  • 無法跨批次 (GO) 跳轉。

四、WAITFOR 延遲/排程


-- 等待 10 秒
WAITFOR DELAY '00:00:10';

-- 等待至指定時間 (若已過則下一天)
WAITFOR TIME '23:59:59';

-- 結合迴圈輪詢
WHILE (SELECT COUNT(*) FROM JobQueue) = 0
    WAITFOR DELAY '00:00:05';  -- 每 5 秒檢查一次
  • DELAY 最大 23:59:59;TIME 為 24 小時制。
  • 會阻塞執行緒,**慎用於高併發核心路徑**;輪詢建議改用 Service Broker / SignalR / 背景工作。

五、TRY ... CATCH 錯誤處理 (SQL 2005+)


BEGIN TRY
    BEGIN TRANSACTION;
    INSERT INTO Orders (...) VALUES (...);
    INSERT INTO OrderItems (...) VALUES (...);
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
    
    -- 取得錯誤資訊
    DECLARE @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrState INT = ERROR_STATE();
    DECLARE @ErrLine INT = ERROR_LINE();
    DECLARE @ErrProc NVARCHAR(200) = ERROR_PROCEDURE();
    
    -- 記錄錯誤日誌
    INSERT INTO ErrorLog (Message, Severity, State, ProcedureName, LineNumber, LogTime)
    VALUES (@ErrMsg, @ErrSeverity, @ErrState, @ErrProc, @ErrLine, SYSDATETIME());
    
    -- 重新拋出 (SQL 2012+ THROW; 舊版 RAISERROR)
    THROW;  -- 保留原始堆疊與狀態
END CATCH
  • 捕捉嚴重度 11-19 的執行階段錯誤;嚴重度 20+ (系統嚴重錯誤) 會中斷連線,無法捕捉。
  • THROW (2012+) 比 RAISERROR 更簡潔、保留原始錯誤號碼/狀態。
  • 交易計數 @@TRANCOUNT 必檢,避免重複 ROLLBACK 報錯。

六、CASE 條件運算式 (兩種形式)

6.1 簡單 CASE (Simple CASE) —— 等值比對


DECLARE @Grade CHAR(1) = 'B';
SELECT 
    CASE @Grade
        WHEN 'A' THEN N'優秀'
        WHEN 'B' THEN N'良好'
        WHEN 'C' THEN N'普通'
        ELSE N'需加強'
    END AS Result;
-- 回傳: 良好
  • 輸入運算式 (@Grade) 與各 WHEN 運算式做**等值比較**。
  • 型別需相容或可隱含轉換。

6.2 搜尋 CASE (Searched CASE) —— 布林運算式


DECLARE @Score INT = 85;
SELECT 
    CASE 
        WHEN @Score >= 90 THEN N'優等'
        WHEN @Score >= 60 THEN N'及格'
        ELSE N'不及格'
    END AS Result;
-- 回傳: 及格
  • **無輸入運算式**;每個 WHEN 為獨立布林運算式,支援範圍、複合條件。
  • **依序評估**,第一個 TRUE 的 THEN 回傳,後續略過。

6.3 CASE 關鍵差異與注意點

特性簡單 CASE搜尋 CASE
輸入運算式有無
WHEN 形式運算式 (等值比對)布林運算式
適用場景離散值映射 (狀態碼、類別)範圍判斷、複合條件
ELSE 省略回傳 NULL回傳 NULL

6.4 進階用法:聚合/排序/分組中使用 CASE


-- 條件聚合
SELECT 
    SUM(CASE WHEN Sex = 'M' THEN 1 ELSE 0 END) AS MaleCount,
    SUM(CASE WHEN Sex = 'F' THEN 1 ELSE 0 END) AS FemaleCount
FROM Students;

-- 動態排序
ORDER BY 
    CASE @SortBy WHEN 'Name' THEN Name WHEN 'Age' THEN CAST(Age AS VARCHAR(10)) END;

-- 動態分組
GROUP BY CASE WHEN Age < 18 THEN 'Minor' ELSE 'Adult' END;

七、程式碼區塊:BEGIN ... END

  • 將多條陳述式視為單一陳述式,用於 IF/ELSE/WHILE/TRY/CATCH 內。
  • 可巢狀;建議縮排對齊提升可讀性。

八、總結:控制流程選型指南

需求推薦結構
單一條件分支IF ... ELSE
多重互斥條件IF ... ELSE IF ... ELSE
離散值映射/轉換簡單 CASE
範圍/複合條件判斷搜尋 CASE
重複執行直到條件變化WHILE
錯誤處理/交易保護TRY ... CATCH
定時/延遲執行WAITFOR
極少數跳轉需求GOTO (最後手段)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved