Сводка, основанная на оригинальном, цитируемом списке ОП.
Да точка с запятой:
Без точки с запятой:
- НАЧИНАЕТСЯ
- ЕСЛИ
- ИЛИ
- НА *
- НАЧИНАЕТСЯ ПОПРОБОВАТЬ
- КОНЕЦ ПОПЫТКИ
- BEGIN CATCH
Кроме того, используйте их после END
и END CATCH
.
Подробности:
BEGIN TRAN
является заявлением и должнозаканчиваться точкой с запятой.
В документации Microsoft указывается необязательная точка с запятой:
BEGIN { TRAN | TRANSACTION }
[ { transaction_name | @tran_name_variable }
[ WITH MARK [ 'description' ] ]
]
[ ; ]
В примере Microsoft есть точки с запятой:
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.120).aspx
Что касается BEGIN...END
, документация Microsoftне дает четких указаний.
В определении нет точки с запятой:
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
Эта конечная точка с запятой не соответствуетСобственная документация 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
Тем не менее, их документация ELSE
, хотя в определении не указана точка с запятой, в примере показывает ее после окончательного END
.
Определение:
IF Boolean_expression { sql_statement | statement_block }
[ ELSE { sql_statement | statement_block } ]
Пример:
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
Стандарт ANSI не разрешает неоднозначность, поскольку это нестандартные расширения:
Операторы управления потоком не охватываются стандартом ANSI SQL, потому что это собственные расширения SQL.Электронная документация по SQL Server отрывочна в этом вопросе, и многие примеры (на момент написания статьи) противоречивы и не всегда включают в себя терминаторы операторов.Кроме того, блоки операторов управления потоком данных сбивают с толку из-за множества вариантов, вложенности и необязательных спецификаций BEGIN / END.
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
Поэтому для самого 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.
Itстановится еще более запутанным.Документация Microsoft для TRY...CATCH
показывает необязательную точку с запятой после END CATCH
, и их примеры соответствуют этому.
BEGIN TRY
{ sql_statement | statement_block }
END TRY
BEGIN CATCH
[ { sql_statement | statement_block } ]
END CATCH
[ ; ]
Однако, если у вас есть CTE сразу после BEGIN 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 говорит, что это нехорошая практика:
Опубликовано Microsoft 12/29/2009 в 12:11 Я решаюсоответствующая ошибка SQL11 как «по замыслу».Вот объяснение:
Точка с запятой между END TRY и BEGIN CATCH не должна быть разрешена, потому что на самом деле это не разные операторы, а части одного и того же оператора TRY-CATCH.Мы допускаем точку с запятой только в том случае, если они разделяют два оператора в последовательности.
Слово объяснения, почему тогда мы допускаем точки с запятой после BEGIN TRY и BEGIN CATCH.Эти ключевые слова служат открывающими «скобками», которые запускают встроенную последовательность операторов.Точки с запятой после 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
точка с запятой не так глупа.