SQL ServerでBegin / End BlocksとGoキーワードを使用する必要があるのはいつですか?


103

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

回答:


116

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

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


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

彼らはコードの論理ブロックをバインドしました。ストアドプロシージャの最初と最後にBEGINとENDを使用する傾向がありますが、厳密には必要ありません。必要なのはループや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

BEGINとENDのないSPを作成してみましたか?IIRC、最初の行のみがSPに含まれ、残りはそこで実行されるだけです...
cjk

2
SQL Server 2000以降の経験は確かにそうではありません。
MatBailie 2010

1
BEGINとENDも新しいスコープを定義していますか?
samis

2
はい。外部で宣言されたものはすべて内部で表示されますが、内部で宣言されたものはすべて、ENDでスコープ外になります。
MatBailie

36

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

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


28

GOはSQL Serverのキーワードではありません。それはバッチセパレータです。GOはステートメントのバッチを終了します。これは、SQLCMDなどを使用している場合に特に便利です。コマンドラインでSQLステートメントを入力するとします。ステートメントを終了するたびに実行する必要はないので、「GO」を入力するまでSQL Serverは何もしません。

同様に、バッチを開始する前に、いくつかのオブジェクトを表示する必要があることがよくあります。たとえば、データベースを作成してクエリを実行するとします。あなたは書くことができません:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

fooは、CREATE TABLEを実行するバッチには存在しないためです。これを行う必要があります:

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

13

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

そうすれば、テストコードでエラーが発生した場合でも、常に開始状態に戻ります。別個のバッチの一部であるbeginおよびrollbackトランザクションステートメントは引き続き発生します。バッチが個別のバッチに含まれていない場合、バッチは1つの単位として解析されるため、構文エラーによりトランザクションの開始が妨げられます。また、実行時エラーが発生すると、ロールバックが発生しなくなります。

また、インストールスクリプトを実行していて、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".

1
「トランザクションはバッチにまたがることができます。変数はバッチにまたがることはできません。」
Gary

3

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

BEGINとENDは、複数のコード行を処理する手続き型ステートメントに必要です。これらは、WHILEループとカーソル(もちろん、可能な限り回避する)とIFステートメント(厳密には、コードが1行しかないIFステートメントには必要ありませんが、簡単に実行できます)に必要です。常にIFの後に配置する場合は、コードを保守してください)。CASEステートメントもENDを使用しますが、BEGINはありません。


GO後のコードは、実際にストアドプロシージャに対して格納されますか?GOが存在しなかった後にコードがあるかのようにCREATEまたはALTERステートメントが処理されませんか?そして、GOの後のコードは、まるでそれが独自のスクリプトであるかのように実行されますか?
MatBailie 2009

カーソルはそれとどのように関係していますか?
ゲイリーマギル

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.