Відповіді:
GO - це як кінець сценарію.
У вас може бути кілька операцій CREATE TABLE, розділених GO. Це спосіб ізолювати одну частину сценарію від іншої, але подати все це в один блок.
BEGIN і END так само, як {і} в 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
Вам потрібно BEGIN ... END, щоб створити блок, що охоплює більше одного оператора. Отже, якщо ви хочете зробити дві речі в одній "нозі" оператора IF, або якщо ви хочете зробити більше ніж одну річ в тілі циклу WHILE, вам потрібно скопіювати ці твердження з BEGIN ... Кінець.
Ключове слово GO не є частиною SQL. Він використовується лише для аналізу запитів для поділу скриптів на "партії", які виконуються самостійно.
GO не є ключовим словом у SQL Server; це пакетний сепаратор. GO закінчує партію тверджень. Це особливо корисно, коли ви використовуєте щось на зразок SQLCMD. Уявіть, що в командному рядку ви вводите оператори SQL. Вам не обов'язково потрібно, щоб річ виконувалася щоразу, коли ви закінчуєте оператор, тому SQL Server нічого не робить, поки ви не введете "GO".
Крім того, перед тим, як розпочнеться партія, вам часто потрібно мати видимі об’єкти. Наприклад, скажімо, ви створюєте базу даних, а потім запитуєте її. Ви не можете написати:
CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;
тому що foo не існує для партії, яка створює СТВОРИТИ ТАБЛИЦЮ. Вам потрібно буде зробити це:
CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;
BEGIN та END добре відповіли інші.
Як вказує Гері, GO - це пакетний сепаратор, який використовується більшістю клієнтських інструментів Microsoft, таких як isql, sqlcmd, аналізатор запитів та студія управління SQL Server. (Принаймні, деякі інструменти дозволяють змінити сепаратор партії. Я ніколи не бачив використання для зміни сепараторного пакету.)
Щоб відповісти на питання про те, коли використовувати 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".
GO закінчує пакет, вам дуже рідко потрібно буде використовувати його в коді. Майте на увазі, що якщо ви використовуєте його в збереженій програмі, жоден код після GO не буде виконаний при виконанні proc.
BEGIN і END потрібні для будь-яких заяв про процедурні типи з декількома рядками коду для обробки. Вони вам знадобляться для циклів і курсорів WHILE (яких ви уникатимете, якщо це можливо, звичайно) та IF-заяв (ну технічно вони вам не потрібні для статті IF, що містить лише один рядок коду, але це простіше підтримуйте код, якщо ви завжди вводите їх після ІФ). У операторах CASE також використовується END, але вони не мають BEGIN.
Після боротьби з цією проблемою сьогодні моя думка така: BEGIN ... END дужки код так само, як {....} робить на мовах C, наприклад, кодові блоки для if else and loops
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 Server SQL-аналізатор SQL Server, на відміну від Oracle, не в змозі зрозуміти, що ви визначаєте новий символ у першому рядку і що це нормально для посилання в наступних рядках. Він не "бачить" символ, поки не зустріне маркер GO, який вказує йому виконувати попередній SQL з останнього GO, і в цей момент символ застосовується до бази даних і не стає видимим для парсера.
Чому він не просто трактує крапку з двокрапкою як семантичну перерву і застосовує заяви окремо, я не знаю і хочу, щоб це було. Єдиний бонус, який я бачу, - це те, що ви можете поставити операцію print () безпосередньо перед GO, і якщо будь-яка з заяв завершиться, друк не виконається. Хоча багато клопоту за незначний виграш.