すべてのT-SQLステートメントの後


34

各SQLステートメントの後にGOステートメントを使用する理由は何ですか?GOはバッチの終了を通知し、ステートメントの評判を許可しますが、ステートメントごとにそれを使用する利点は何ですか。

声明のたびに多くのマイクロソフトのドキュメントなどが使用を開始したか、気づき始めたばかりかもしれません。

また、ベストプラクティスと見なされるものは何ですか?

回答:


51

使用するタイミングと理由に答える前GOに、何が何で、何がそうでないかを正確に理解することが最重要です。

このキーワードGOは、SQL Server Management StudioおよびSQLCMDで、1つのことだけを示すために使用されます。ステートメントのバッチの終わりです。実際、バッチを終了するために使用するものを「GO」以外に変更することもできます。

ここに画像の説明を入力してください

上記のスクリーンショットは、構成可能なSSMS内のオプションです。

しかし、バッチとは何ですか?? このBOLリファレンスは、それを最もよく言っています:

バッチは実行のためにアプリケーションからSQL Serverに同時に送信される1つ以上のTransact-SQLステートメントのグループです

そのような単純な。これは、アプリケーション(はい...アプリケーション)がSQL Serverにステートメントを送信する単なるカスタム方法です。これのアプリケーションに見える例を見てみましょう。PowerShellを使用して、ステートメントとバッチをSQL Serverに送信するためにアプリケーションが行うことを模倣します。

$ConnectionString = "data source = SomeSQLInstance; initial catalog = AdventureWorks2012; trusted_connection = true; application name = BatchTesting;"

try {
    $SqlConnection = New-Object System.Data.SqlClient.SqlConnection($ConnectionString)
    $SqlCmd = New-Object System.Data.SqlClient.SqlCommand
    $SqlCmd.Connection = $SqlConnection

    # first batch of statements
    #
    $SqlCmd.CommandText = "
        select * from humanresources.department where departmentid = 1;
        select * from humanresources.department where departmentid = 2;
        select * from humanresources.department where departmentid = 3;
        select * from humanresources.department where departmentid = 4;"

    # execute the first batch
    #
    $SqlConnection.Open()
    $SqlCmd.ExecuteNonQuery()
    $SqlConnection.Close()

    # second batch of statements
    #
    $SqlCmd.CommandText = "
        select * from humanresources.department where departmentid = 5;
        select * from humanresources.department where departmentid = 6;
        select * from humanresources.department where departmentid = 7;
        select * from humanresources.department where departmentid = 8;"

    # execute the second batch
    #
    $SqlConnection.Open()
    $SqlCmd.ExecuteNonQuery()
    $SqlConnection.Close()
}
catch {
    $SqlCmd.Dispose()
    $SqlConnection.Dispose()
    Write-Error $_.Exception
}

コメントでわかりますが、上記のように、プログラムで2つのバッチをSQL Serverに送信していることがわかります。ただし、それを確認しましょう。ここでの私の選択は、拡張イベントを使用することです。

create event session BatchTesting
on server
add event sqlserver.sql_batch_starting
(
    set
        collect_batch_text = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_batch_completed
(
    set
        collect_batch_text = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_statement_starting
(
    set
        collect_statement = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_statement_completed
(
    set
        collect_statement = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
)
add target package0.event_file
(
    set
        filename = N'<MyXelLocation>\BatchTesting.xel'
);
go

alter event session BatchTesting
on server
state = start;
go

このXEventsセッションが実行しているのは、次の名前のアプリケーションから開始および完了するステートメントとバッチをキャプチャすることです "BatchTesting"ことです(PowerShellコード例で接続文字列に気付いた場合は、「application 「名前」接続文字列パラメータとそのフィルタリング)。

PowerShellコードを実行してこれらのバッチとステートメントを送信すると、次の結果が表示されます。

ここに画像の説明を入力してください

スクリーンショットからわかるように、ステートメントが2つの異なるバッチにどのように分割されているかは明らかです。これは、バッチを呼び出すために使用した手段でも明らかです。batch_textの最初の出現を調べると、sql_batch_startingそのバッチに含まれるすべてのステートメントを見ることができます。

    select * from humanresources.department where departmentid = 1;
    select * from humanresources.department where departmentid = 2;
    select * from humanresources.department where departmentid = 3;
    select * from humanresources.department where departmentid = 4;

バッチとは何かについての説明とともに、バッチをいつ終了するかという質問に対する答えが得られます。バッチのルールは、バッチに関するこのBOLリファレンスに記載されています

CREATE DEFAULT、CREATE FUNCTION、CREATE PROCEDURE、CREATE RULE、CREATE SCHEMA、CREATE TRIGGER、およびCREATE VIEWステートメントは、バッチ内の他のステートメントと組み合わせることはできません。CREATEステートメントはバッチを開始する必要があります。そのバッチに続く他のすべてのステートメントは、最初のCREATEステートメントの定義の一部として解釈されます。

テーブルを変更してから、同じバッチで新しい列を参照することはできません。

EXECUTEステートメントがバッチの最初のステートメントである場合、EXECUTEキーワードは必要ありません。EXECUTEステートメントがバッチ内の最初のステートメントでない場合、EXECUTEキーワードが必要です。

同様に、バッチ中に発生する特定のランタイムエラー(コンパイルエラーではバッチの実行が許可されない)は、さまざまな動作を引き起こす可能性があります:バッチを完全に中止するか、バッチを続行して問題のあるステートメントのみを中止します(上記リンクには、2つの非常に良い例があります。たとえば、算術オーバーフローエラーはバッチの実行を停止しますが、制約違反エラーは現在のステートメントの完了を妨げますが、バッチの実行は継続します。

しかし、私たちの専門家の多くのものと同様に、個人的な好みは、T-SQLコードの個人およびライターとしてのあなたがどのようにバッチを終了するかを支える大きな推進力になります。絶対に必要な場合にのみバッチを明示的に定義する人(上記の要件を参照)と、SSMSのクエリウィンドウで1つのステートメントのみを実行している場合でも、バッチをプログラムで100%終了する人もいます。ほとんどの人は通常、これらの2つの境界の中間に位置します。価値のあることとして、ステートメントターミネーターには同じ要件があり、強制要件もほとんどありません。このすべての大部分はコードスタイルであり、強制されていません(SSMSおよびSQLCMDで)。


おそらく素朴なコメントかもしれませんが、SQL Serverがバッチ自体で何を実行するかを決定できたと思います(他の多くの最適化がデータベースエンジンによって処理されるのと同じ方法で)。たとえば、ユーザーがスクリプトを作成するのではなく、説明したルールを使用すると、エラーが発生しやすくなり、スクリプトに不要な膨張を追加する可能性があります。
スティーブチェンバース

1
@SteveChambers正確に私の感情。答えは「それはそれと同じくらい簡単です」(バッチは、実行のためにアプリケーションからSQL Serverに同時に送信される1つ以上のTransact-SQLステートメントのグループです。)しかし、そうではありません。失敗してバッチで送信しようとしたステートメントの組み合わせがあります。最終的に私はあなたが理解する必要があると思う理由方法:私は最終的にこの1に私自身の答えを貢献して-バッチを送信することは、個々のステートメントのセットを送信するよりも異なっているstackoverflow.com/a/56370223/3714936 -また、あなたのコメントに話します。
youcantryreachingme
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.