Когда мне нужно использовать Begin / End Blocks и ключевое слово Go в SQL Server?


103

Может кто - нибудь сказать мне , когда и где мне нужно использовать beginи endблоки в SQL Server?
Кроме того, что именно делает Goключевое слово?

Ответы:


116

GO похож на конец сценария.

У вас может быть несколько операторов CREATE TABLE, разделенных GO. Это способ изолировать одну часть скрипта от другой, но отправить все в одном блоке.


BEGIN и END аналогичны {and} в C / ++ / #, Java и т. Д.

Они связывают логический блок кода. Я обычно использую BEGIN и END в начале и в конце хранимой процедуры, но здесь это не обязательно. Там, где это необходимо, это для циклов, операторов IF и т.д., где вам нужно более одного шага ...

IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
   INSERT INTO Log SELECT @id, 'deleted'
   DELETE my_table WHERE id = @id
END

Вы пробовали создать SP без BEGIN и END? IIRC, только первая строка включена в SP, остальное просто выполняется тут же ...
cjk 07

2
Это, конечно, не мой опыт, начиная с SQL Server 2000 и далее.
MatBailie,

1
Определяют ли BEGIN и END новую область видимости?
Samis

2
Да. Все, что объявлено снаружи, видно внутри, но все, что объявлено внутри, выйдет за пределы области действия в конце.
MatBailie

36

Вам нужно BEGIN ... END, чтобы создать блок, охватывающий более одного оператора. Итак, если вы хотите сделать две вещи в одной «ветке» оператора IF или если вы хотите сделать более одной операции в теле цикла WHILE, вам нужно заключить эти операторы в скобки с BEGIN ... КОНЕЦ.

Ключевое слово GO не является частью SQL. Он используется только Query Analyzer для разделения скриптов на «пакеты», которые выполняются независимо.


28

GO не является ключевым словом в SQL Server; это разделитель партий. GO завершает серию заявлений. Это особенно полезно, когда вы используете что-то вроде SQLCMD. Представьте, что вы вводите операторы SQL в командной строке. Вы не обязательно хотите, чтобы это выполнялось каждый раз, когда вы завершаете инструкцию, поэтому SQL Server ничего не делает, пока вы не введете «GO».

Точно так же перед запуском партии вам часто нужно, чтобы некоторые объекты были видны. Например, предположим, что вы создаете базу данных, а затем запрашиваете ее. Вы не можете написать:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

потому что foo не существует для пакета, который выполняет CREATE TABLE. Вам нужно будет сделать это:

CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;

13

Другие хорошо ответили на BEGIN и END.

Как указывает Гэри, GO - это разделитель пакетов, используемый большинством клиентских инструментов Microsoft, таких как isql, sqlcmd, анализатор запросов и SQL Server Management Studio. (По крайней мере, некоторые инструменты позволяют менять разделитель партий. Я никогда не видел, чтобы использовать смену разделителя партий.)

Чтобы ответить на вопрос, когда использовать GO, нужно знать, когда SQL должен быть разделен на пакеты.

Некоторые операторы должны быть первым оператором пакета.

select 1
create procedure #Zero as
    return 0

В SQL Server 2000 ошибка:

Msg 111, Level 15, State 1, Line 3
'CREATE PROCEDURE' must be the first statement in a query batch.
Msg 178, Level 15, State 1, Line 4
A RETURN statement with a return value cannot be used in this context.

В SQL Server 2005 ошибка менее полезна:

Msg 178, Level 15, State 1, Procedure #Zero, Line 5
A RETURN statement with a return value cannot be used in this context.

Таким образом, используйте GOдля разделения операторов, которые должны быть началом пакета, от операторов, которые предшествуют ему в сценарии.

При запуске сценария многие ошибки приводят к остановке выполнения пакета, но тогда клиент просто отправит следующий пакет, выполнение сценария не остановится. Я часто использую это при тестировании. Я начну скрипт с начала транзакции и закончу откатом, проведя все тестирование посередине:

begin transaction
go
... test code here ...
go
rollback transaction

Таким образом, я всегда возвращаюсь в начальное состояние, даже если в тестовом коде произошла ошибка, операторы транзакции начала и отката, являющиеся частью отдельных пакетов, все равно выполняются. Если бы они не находились в отдельных пакетах, то синтаксическая ошибка не позволяла бы начать транзакцию, поскольку пакет анализируется как единое целое. А ошибка времени выполнения помешает откату.

Кроме того, если вы выполняете сценарий установки и имеете несколько пакетов в одном файле, ошибка в одном пакете не помешает сценарию продолжить работу, что может привести к беспорядку. (Всегда делайте резервную копию перед установкой.)

В связи с тем, что указал Дэйв Маркел, бывают случаи, когда синтаксический анализ завершается неудачно, потому что SQL Server ищет в словаре данных объекты, созданные ранее в пакете, но синтаксический анализ может происходить до запуска каких-либо операторов. Иногда это проблема, иногда нет. Я не могу привести хороший пример. Но если вы когда-нибудь получите ошибку «X не существует», когда она явно будет существовать, этот оператор разбивается на партии.

И последнее замечание. Транзакция может охватывать партии. (См. Выше.) Переменные не охватывают партии.

declare @i int
set @i = 0
go
print @i

Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".

1
Это то, что мне нужно, спасибо: «Транзакция может охватывать пакеты. Переменные не охватывают пакеты».
Гэри

3

GO завершает пакет, вам очень редко понадобится использовать его в коде. Имейте в виду, что если вы используете его в сохраненной процедуре, никакой код после GO не будет выполняться при выполнении процедуры.

BEGIN и END необходимы для любых операторов процедурного типа с несколькими строками кода для обработки. Они понадобятся вам для циклов и курсоров WHILE (которых вы, конечно же, избегаете, если это вообще возможно) и операторов IF (ну, технически они вам не нужны для состояния IF, в котором есть только одна строка кода, но это проще поддерживать код, если вы всегда вставляете их после IF). Операторы CASE также используют END, но не имеют BEGIN.


Будет ли какой-либо код после GO действительно сохраняться в сохраненной процедуре? не будет ли оператор CREATE или ALTER обрабатываться, как если бы кода после GO не существовало? И ТОГДА код после GO будет выполнен, как если бы это был собственный скрипт?
MatBailie,

При чем тут курсоры?
Gary McGill,

3

После того, как я поборол эту проблему сегодня, мое мнение таково: BEGIN ... END код в скобках точно так же, как {....} в языках C, например, блоки кода для if ... else и циклы

GO используется (должен использоваться), когда последующие операторы полагаются на объект, определенный предыдущим оператором. База данных USE - хороший пример выше, но вас укусит и следующее:

alter table foo add bar varchar(8);
-- if you don't put GO here then the following line will error as it doesn't know what bar is.
update foo set bar = 'bacon';
-- need a GO here to tell the interpreter to execute this statement, otherwise the Parser will lump it together with all successive statements.

Мне кажется, проблема в следующем: SQL-парсер SQL Server, в отличие от Oracle, не может понять, что вы определяете новый символ в первой строке и что можно ссылаться на следующие строки. Он не «видит» символ, пока не встретит токен GO, который сообщает ему выполнить предыдущий SQL с момента последнего GO, после чего символ применяется к базе данных и становится видимым для анализатора.

Почему он не обрабатывает точку с запятой просто как семантический разрыв и не применяет инструкции индивидуально, я не знаю и хотел бы, чтобы это было. Единственный бонус, который я вижу, это то, что вы можете поместить оператор print () непосредственно перед GO, и если какой-либо из операторов не сработает, печать не будет выполнена. Однако много хлопот ради незначительной выгоды.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.