摘要,基于 OP 的原始引用列表。
是的分号:
没有分号:
- BEGIN
- IF
- ELSE
- WHILE
- 开始尝试
- END TRY
- 开始捕捉
另外,在之后使用它们END
and END CATCH
.
Details:
BEGIN TRAN
是一个语句,应该以分号结束。
微软的文档指出了可选的分号:
BEGIN { TRAN | TRANSACTION }
[ { transaction_name | @tran_name_variable }
[ WITH MARK [ 'description' ] ]
]
[ ; ]
微软的例子有分号:
BEGIN TRAN T1;
UPDATE table1 ...;
BEGIN TRAN M2 WITH MARK;
UPDATE table2 ...;
SELECT * from table1;
COMMIT TRAN M2;
UPDATE table3 ...;
COMMIT TRAN T1;
以上两篇均来自:
https://msdn.microsoft.com/en-us/library/ms188929(v=sql.90).aspx https://msdn.microsoft.com/en-us/library/ms188929(v=sql.90).aspx
它们与当前文档匹配:
https://msdn.microsoft.com/en-us/library/ms188929(v=sql.120).aspx https://msdn.microsoft.com/en-us/library/ms188929(v=sql.120).aspx
As for BEGIN...END
,微软文档没有提供明确的指导。
该定义没有分号:
BEGIN
{
sql_statement | statement_block
}
END
然而,他们的示例在 END 之后显示了一个分号:
IF @@TRANCOUNT = 0
BEGIN
SELECT FirstName, MiddleName
FROM Person.Person WHERE LastName = 'Adams';
ROLLBACK TRANSACTION;
PRINT N'Rolling back the transaction two times would cause an error.';
END;
https://msdn.microsoft.com/en-us/library/ms190487.aspx https://msdn.microsoft.com/en-us/library/ms190487.aspx
该尾随分号与 Microsoft 自己的文档不一致IF
流语言构造的控制:
IF Boolean_expression
{ sql_statement | statement_block }
[ ELSE
{ sql_statement | statement_block } ]
该定义及其代码示例均未显示任何分号:
DECLARE @compareprice money, @cost money
EXECUTE Production.uspGetList '%Bikes%', 700,
@compareprice OUT,
@cost OUTPUT
IF @cost <= @compareprice
BEGIN
PRINT 'These products can be purchased for less than
$'+RTRIM(CAST(@compareprice AS varchar(20)))+'.'
END
ELSE
PRINT 'The prices for all products in this category exceed
$'+ RTRIM(CAST(@compareprice AS varchar(20)))+'.'
https://msdn.microsoft.com/en-us/library/ms182717(v=sql.110).aspx https://msdn.microsoft.com/en-us/library/ms182717(v=sql.110).aspx
然而,他们的ELSE
文档虽然在定义中也没有显示任何分号,但在示例中的最后一个分号之后确实显示了一个分号END
.
定义:
IF Boolean_expression { sql_statement | statement_block }
[ ELSE { sql_statement | statement_block } ]
Example:
IF 1 = 1 PRINT 'Boolean_expression is true.'
ELSE PRINT 'Boolean_expression is false.' ;
https://msdn.microsoft.com/en-us/library/ms182587(v=sql.110).aspx https://msdn.microsoft.com/en-us/library/ms182587(v=sql.110).aspx
ANSI 标准无法解决歧义,因为这些是非标准扩展:
ANSI SQL 标准不涵盖控制流语句
因为这些是专有的 SQL 扩展。 SQL Server 书籍
网上关于这个主题和许多例子都是粗略的(截至此
写作)不一致并且并不总是包含声明
终结者。此外,控制流语句块是
由于许多变化、嵌套和可选的开始/结束而令人困惑
规格。
http://www.dbdelta.com/always-use-semicolon-statement-terminators/ http://www.dbdelta.com/always-use-semicolon-statement-terminators/
然而,服务器的行为揭示了一些线索。以下不是 SQL Server 2005 中的语法错误:
DECLARE @foo int;
IF @foo IS NULL
BEGIN
WITH Blah AS
(
SELECT
'a' AS a
)
SELECT
a
FROM Blah;
END
So the BEGIN
本身不需要分号。但是,以下内容在 SQL Server 2005 中确实会产生语法错误:
DECLARE @foo int;
IF @foo IS NULL
BEGIN
WITH Blah AS
(
SELECT
'a' AS a
)
SELECT
a
FROM Blah;
END
WITH Blah2 AS
(
SELECT
'a' AS a
)
SELECT
a
FROM Blah2;
上述结果导致此错误:
消息 319,级别 15,状态 1,第 13 行关键字附近的语法不正确
'和'。如果该语句是公用表表达式或
xmlnamespaces 子句中,前面的语句必须以
分号。
它还会在 SQL Server 2008 R2 中引发该错误。
这变得更加令人困惑。微软的文档TRY...CATCH
在后面显示一个可选的分号END CATCH
,他们的例子与此一致。
BEGIN TRY
{ sql_statement | statement_block }
END TRY
BEGIN CATCH
[ { sql_statement | statement_block } ]
END CATCH
[ ; ]
但是,如果您在接受治疗后立即出现 CTEBEGIN TRY
,如果没有分号,就会抛出错误。
BEGIN TRY
WITH Blah AS
(
SELECT
'a' AS a
)
SELECT
a
FROM Blah;
END TRY
BEGIN CATCH
END CATCH
在 SQL Server 2008 R2 中,上述批处理会引发此错误:
消息 319,级别 15,状态 1,第 2 行 关键字附近的语法不正确
'和'。如果该语句是公用表表达式,则
xmlnamespaces 子句或更改跟踪上下文子句,前面的
语句必须以分号结束。
该错误意味着BEGIN TRY
是一个声明(它不是),并且分号“修复”了问题(它确实解决了)。没错,这有效:
BEGIN TRY;
WITH Blah AS
(
SELECT
'a' AS a
)
SELECT
a
FROM Blah;
END TRY
BEGIN CATCH
END CATCH
然而,微软表示这不是一个好的做法:
Microsoft 发布于 12/29/2009 下午 12:11 我正在解决
将 SQL11 错误对应为“设计使然”。解释如下:
END TRY 和 BEGIN CATCH 之间不允许有分号,
因为它们实际上并不是不同的陈述,而是陈述的一部分
相同的 TRY-CATCH 语句。我们只允许在分隔时使用分号
一个序列中的两个语句。
解释一下为什么我们在 BEGIN TRY 和之后允许使用分号
开始捕捉。这些关键字充当开始的“括号”
嵌入的语句序列。 BEGIN TRY/BEGIN CATCH 之后的分号
被解析为嵌入序列的一部分,其中包含第一条语句
在空的序列中。虽然我们允许这种语法,但我不会
推荐它作为良好的编码实践,因为它会产生错误
BEGIN TRY/BEGIN CATCH 的印象是独立的、独立的
声明。
处理这种情况的推荐方法是使用额外的BEGIN...END
为了清楚起见:
BEGIN TRY
BEGIN
WITH Blah AS
(
SELECT
'a' AS a
)
SELECT
a
FROM Blah;
END
END TRY
BEGIN CATCH
END CATCH
然而,那END
之前END TRY
可能应该有一个分号。毕竟,这会引发错误:
BEGIN TRY
BEGIN
WITH Blah AS
(
SELECT
'a' AS a
)
SELECT
a
FROM Blah;
END
WITH Blah2 AS
(
SELECT
'b' AS b
)
SELECT
b
FROM Blah2;
END TRY
BEGIN CATCH
END CATCH
也许总是在 CTE 之前WITH
分号并不那么愚蠢。