分享方式:


開始。。。結束(Transact-SQL)

適用於:SQL ServerAzure SQL 資料庫Azure SQL 受控執行個體Azure Synapse Analytics分析平台系統(PDW)Microsoft Fabric 中的 SQL 分析端點Microsoft Fabric 中的倉儲Microsoft Fabric 中的 SQL 資料庫

將一連串 Transact-SQL 語句包圍在一個邏輯程式碼區塊中。 這種用法 BEGINBEGIN TRANSACTION and BEGIN ATOMIC 陳述無關。

你可以使用BEGIN...END前置有 、 IFELSE、 和 WHILE的區塊。 不過,你也可以使用這些區塊,而不使用任何前置的流量控制語句,以有組織的方式將一連串語句分組。 然而,每個新 BEGIN...END 區塊並不會產生新的詞彙範圍。

Transact-SQL 語法慣例

Syntax

BEGIN [ ; ]
    { sql_statement | statement_block }
END [ ; ]

Arguments

{ sql_statement | statement_block}

使用語句區塊所定義的任何有效 Transact-SQL 語句或語句群組。

Remarks

一個 BEGIN...END 區塊必須包含至少一個語句。 如果你嘗試使用空 BEGIN...END 區塊,即使你在每個關鍵字後面加分號,也會有語法錯誤。 你可以透過使用GOTO標籤作為佔位語句來避免BEGIN...END空區塊。 參見 範例 C:使用動態產生的 BEGIN... 的 GOTO 標籤。終結區塊

BEGIN...END 區塊可以是巢狀的。

BEGIN...END 區塊並不定義任何詞彙範圍。 如果你在區塊內宣告變數,它會在整個父批次中可見,而不僅限於包含該 DECLARE 語句的區塊內。

你不能在多個批次間使用 BEGIN...END 區塊。 例如,你不能在區塊內BEGIN...END使用GO批次分離器。

BEGIN...END 區塊來分組語句並不代表群組裡的所有語句都以原子方式執行。 當批次在交易外執行,且多重陳述 BEGIN...END 區塊的第二個陳述句提出錯誤或拋出異常時,第一個陳述句不會被回滾。

與 關鍵字後BEGIN的分號為可選,但建議使用,除非以下情況:END

  • 你需要在關鍵字前 WITH 加分號,才能開啟 常見表格表達 式(CTE)。

  • 你需要一個分號,且陳述 THROW 句在一個區塊內。

  • 後面用分號 BEGIN 避免與 BEGIN TRANSACTION or BEGIN ATOMIC 語句混淆。

  • 使用分號後 END 可確保後續語句,特別是 WITH 關鍵字或 THROW 語句,前方不需加分號。

雖然所有 Transact-SQL 語句在區 BEGIN...END 塊內都有效,但你不應該將某些 Transact-SQL 語句集中在同一批次或語句區塊中。 確保報價不會與現有的 Transact-SQL 批次需求衝突。

Examples

本文中的程式代碼範例會使用 AdventureWorks2025AdventureWorksDW2025 範例資料庫,您可以從 Microsoft SQL Server 範例和社群專案 首頁下載。

在以下範例中, BEGINEND 定義邏輯相關的 Transact-SQL 語句序列,依序執行。 範例中也展示了巢狀區塊。

USE AdventureWorks2025;
GO

DECLARE @personId AS INT = (
    SELECT p.BusinessEntityID
    FROM Person.Person AS p
    WHERE p.rowguid = { GUID '92C4279F-1207-48A3-8448-4636514EB7E2' }
);

IF (@personId IS NULL)
    THROW 50001, 'Person not found.', 1;

/* Concatenate the person's name fields: */;
BEGIN
    DECLARE @title AS NVARCHAR (8),
            @first AS NVARCHAR (50),
            @middle AS NVARCHAR (50),
            @last AS NVARCHAR (50),
            @suffix AS NVARCHAR (10);

    SELECT @title = NULLIF (p.Title, N''),
           @first = p.FirstName,
           @middle = NULLIF (p.MiddleName, N''),
           @last = p.LastName,
           @suffix = NULLIF (p.Suffix, N'')
    FROM Person.Person AS p
    WHERE p.BusinessEntityID = @personId;

    DECLARE @nameConcat AS NVARCHAR (255) = CONCAT_WS(N' ', @title, @first, @middle, @last, @suffix);

    /* This is a nested BEGIN...END block: */;
    BEGIN
        DECLARE @emails AS NVARCHAR (MAX) = (
            SELECT STRING_AGG(e.EmailAddress, /*separator:*/N'; ')
            FROM Person.EmailAddress AS e
            WHERE e.BusinessEntityID = @personId
        );

        SET @nameConcat = CONCAT(@nameConcat, N' (', @emails, N')');
    END
END

/* BEGIN...END blocks do not define a lexical scope, so
   even though @nameAndEmails is declared above, it is
   still in-scope after the END keyword. */
SELECT @nameConcat AS NameAndEmails;

B. 使用 BEGIN...交易中的 END

在下列範例中,BEGINEND 會定義一系列同時執行的 Transact-SQL 陳述式。 如果沒有包含該 BEGIN...END 區塊,兩個 ROLLBACK TRANSACTION 語句都會執行,並回傳兩個 PRINT 訊息。

USE AdventureWorks2025;
GO

BEGIN TRANSACTION;

IF @@TRANCOUNT = 0
    BEGIN
        SELECT FirstName,
               MiddleName
        FROM Person.Person
        WHERE LastName = 'Adams';

        ROLLBACK TRANSACTION;

        PRINT N'Rolling back the transaction two times causes an error.';
    END

ROLLBACK TRANSACTION;

PRINT N'Rolled back the transaction.';

C. 動態產生的 BEGIN... 使用GOTO標籤。端區塊

如果你用區塊產生動態 Transact-SQL BEGIN...END ,且想讓程式永遠渲染 BEGIN...END 關鍵字,可以用 GOTO 標籤作為佔位語句,避免區塊是 BEGIN...END 空的。

BEGIN
    unusedLabel:
END

範例:Azure Synapse Analytics 和 Analytics Platform System (PDW)

C. 定義一系列連貫的陳述

在以下範例中,BEGINEND 會定義一系列同時執行的 SQL 陳述式。

謹慎

如果你移除 BEGINEND 關鍵字,以下範例會進入無限迴圈。 該 WHILE 語句只迴圈查詢, SELECT 且從未進入該 SET @Iteration += 1 語句。

-- Uses AdventureWorksDW;
DECLARE @Iteration AS INT = 0;

WHILE @Iteration < 10
    BEGIN
        SELECT FirstName,
               MiddleName
        FROM dbo.DimCustomer
        WHERE LastName = 'Adams';
        SET @Iteration + = 1;
    END