web-dev-qa-db-ja.com

SQL Serverで開始/終了ブロックとGoキーワードを使用する必要があるのはいつですか?

SQL Serverでbeginブロックとendブロックをいつ、どこで使用する必要があるかを教えてもらえますか?
また、Goキーワードは正確に何をしますか?

96
Tarik

GOはスクリプトの終わりのようなものです。

GOで区切られた複数のCREATE TABLEステートメントを使用できます。これは、スクリプトの一部を別の部分から分離する方法ですが、すべてを1つのブロックで送信します。


BEGINとENDは、C/++ /#、Javaなどの{と}と同じです。

コードの論理ブロックをバインドしました。ストアドプロシージャの開始時と終了時にBEGINとENDを使用する傾向がありますが、そこでは厳密には必要ありません。それがIS必要なのは、ループやIFステートメントなど、1つ以上のステップが必要な場合です...

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

複数のステートメントにまたがるブロックを作成するには、BEGIN ... ENDが必要です。したがって、IFステートメントの1つの「脚」で2つのことをしたい場合、またはWHILEループの本体で複数のことをしたい場合は、これらのステートメントをBEGINで囲む必要があります...終わり。

GOキーワードはSQLの一部ではありません。クエリアナライザーは、スクリプトを独立して実行される「バッチ」に分割するためにのみ使用します。

34
Gary McGill

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;
25
Dave Markle

BEGINとENDは他の人からよく回答されています。

Garyが指摘するように、GOはバッチセパレーターであり、isql、sqlcmd、クエリアナライザー、SQL Server Management Studioなど、Microsoftが提供するほとんどのクライアントツールで使用されます。 (少なくとも一部のツールでは、バッチセパレーターを変更できます。バッチセパレーターを変更する用途は見たことがありません。)

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

そのようにして、テストコードでエラーが発生した場合でも、常に開始状態に戻りますが、個別のバッチの一部であるトランザクションステートメントの開始とロールバックは引き続き発生します。それらが別々のバッチにない場合、構文エラーによりバッチがユニットとして解析されるため、トランザクションの開始が妨げられます。また、ランタイムエラーが発生すると、ロールバックが発生しなくなります。

また、インストールスクリプトを実行していて、1つのファイルに複数のバッチがある場合、1つのバッチでエラーが発生してもスクリプトの実行は継続されず、混乱が生じる可能性があります。 (インストールする前に常にバックアップします。)

Dave Markelが指摘したことに関連して、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".
10

今日、この問題に取り組んだ後、私の意見はこうです:BEGIN ... ENDは、C言語で{....}がするようにコードをブラケットします。 if ... elseおよびloopのコードブロック

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.

問題はこれだと思われます。SQLServer SQLパーサーは、Oracleとは異なり、最初の行で新しいシンボルを定義していること、および次の行で参照しても問題ないことを認識できません。最後のGO以降に先行するSQLを実行するように指示するGOトークンに遭遇するまで、シンボルは「表示」されません。その時点で、シンボルがデータベースに適用され、パーサーに表示されます。

なぜセミコロンをセマンティックブレークとして扱い、個別にステートメントを適用しないのか、私にはわかりません。私が見ることができる唯一のボーナスは、GOの直前にprint()ステートメントを置くことができ、ステートメントのいずれかが失敗すると印刷が実行されないことです。マイナーな利益のためのトラブルがたくさん。

2
matao

GOはバッチを終了します。コードで使用する必要はほとんどありません。ストアドプロシージャで使用する場合、そのプロシージャを実行するときにGOの後のコードは実行されないことに注意してください。

BEGINおよびENDは、処理する複数行のコードを含む手続き型ステートメントに必要です。 WHILEループとカーソル(もちろん可能な限り回避します)およびIFステートメント(技術的には1行のコードしか持たないIFステートメントには必要ありませんが、より簡単です)に必要になります。常にIFの後に挿入する場合は、コードを維持してください)。 CASEステートメントもENDを使用しますが、BEGINはありません。

2
HLGEM