适用于:SQL Server
Azure SQL 数据库
Azure SQL 托管实例
Azure Synapse Analytics
分析平台系统(PDW)
Microsoft Fabric 中的 SQL 分析终结点
Microsoft Fabric 中的仓库
Microsoft Fabric 中的 SQL 数据库
将 Transact-SQL 语句序列包裹在逻辑代码块中。 这种用法 BEGIN 与 BEGIN TRANSACTION 和 BEGIN ATOMIC 语句无关。
你可以使用 BEGIN...END 带有前置流量控制语句的块,如 IF、 ELSE、 WHILE和 。 不过,你也可以在没有任何前置流量控制语句的情况下使用这些块,以有组织的方式将语句序列分组。 然而,每个新 BEGIN...END 区块并不会创造新的词汇范围。
Syntax
BEGIN [ ; ]
{ sql_statement | statement_block }
END [ ; ]
Arguments
{ sql_statementstatement_block}
使用语句块定义的任何有效的 Transact-SQL 语句或语句分组。
Remarks
一个 BEGIN...END 块必须包含至少一个语句。 如果你尝试使用空 BEGIN...END 块,即使你在每个关键词后加分号,也会导致语法错误。 你可以通过使用GOTO标签作为占位语句来避免BEGIN...END空块。 参见 示例C:使用GOTO标签表示动态生成的BEGIN...终结块。
BEGIN...END 块可以嵌套。
BEGIN...END 区块并不定义任何词汇范围。 如果你在某个块内声明变量,它在整个父批处理中都能看到,而不仅仅是包含该 DECLARE 语句的块内。
你不能在多个批次中使用 BEGIN...END 区块。 例如,你不能在块内BEGIN...END使用GO批分隔器。
用 BEGIN...END 块来分组语句并不意味着组内的所有语句都以原子方式运行。 当批处理在事务外运行,且多语句 BEGIN...END 块的第二个语句引发错误或抛出异常时,第一个语句不会被回滚。
和 关键字后的BEGIN分号为可选,但建议使用,除非以下情况:END
你需要在开头的关键词前
WITH加分号,作为 常用表表达式 (CTE)。你需要一个分号,并且在一个区块内有语
THROW句。后面用分号
BEGIN避免与BEGIN TRANSACTION“或BEGIN ATOMIC”语句混淆“。使用分号后
END可确保后续任何语句,尤其是WITH关键词或THROW语句,都不需要前置分号。
虽然所有 Transact-SQL 语句在一个 BEGIN...END 区块内都是有效的,但你不应该将某些 Transact-SQL 语句集中在同一批次或语句块中。 确保对账单不与现有 Transact-SQL 批次要求冲突。
Examples
本文中的代码示例使用 AdventureWorks2025 或 AdventureWorksDW2025 示例数据库,可以从 Microsoft SQL Server 示例和社区项目 主页下载该数据库。
答: 按顺序定义一系列逻辑相关的语句
在下例中, BEGIN 定义 END 逻辑相关的 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
在下面的示例中,BEGIN 和 END 定义一系列一起执行的 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. 使用GOTO标签表示动态生成的BEGIN...端块
如果你用一个块生成动态 Transact-SQL BEGIN...END ,并且希望程序始终渲染关键 BEGIN...END 词,可以用 GOTO 标签作为占位语句,避免块是 BEGIN...END 空的。
BEGIN
unusedLabel:
END
示例:Azure Synapse Analytics 和 Analytics Platform System (PDW)
C. 定义一系列连贯的语句
在下面的示例中,BEGIN 和 END 定义一系列一起运行的 SQL 语句。
注意
如果去除 BEGIN 和 END 关键字,下面的示例会进入无限循环。 该 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