web-dev-qa-db-ja.com

SQL ServerのT-SQL STOPまたはABORTコマンド

スクリプトに処理を停止するように指示するコマンドがMicrosoft SQL Server T-SQLにありますか?アーカイブの目的で保持したいスクリプトがありますが、誰にも実行させたくありません。

50
Phillip Senn

別の解決策は、GOTOステートメントを使用してスクリプトの実行フローを変更することです...

DECLARE  @RunScript bit;
SET @RunScript = 0;

IF @RunScript != 1
BEGIN
RAISERROR ('Raise Error does not stop processing, so we will call GOTO to skip over the script', 1, 1);
GOTO Skipper -- This will skip over the script and go to Skipper
END

PRINT 'This is where your working script can go';
PRINT 'This is where your working script can go';
PRINT 'This is where your working script can go';
PRINT 'This is where your working script can go';

Skipper: -- Don't do nuttin!

警告!上記のサンプルは、Merrill Aldrichから入手した例から派生したものです。 GOTOステートメントを盲目的に実装する前に、 T-SQLスクリプトのフロー制御 に関するチュートリアルを読むことをお勧めします。

45
Jed

いいえ、ありません-いくつかのオプションがあります:

  1. 単純に真ではないことが保証されている大きなif/endブロックでスクリプト全体をラップします(つまり、「if 1 = 2 begin」-ただし、スクリプトにGOステートメントが含まれていない場合にのみ機能します(新しいバッチ)

  2. 上部のreturnステートメントを使用します(これもバッチセパレーターによって制限されます)

  3. 接続ベースのアプローチを使用します。これにより、スクリプト全体が非実行になります(接続全体がより正確になります)。 'SET PARSEONLY ON' または 'SET NOEXEC ON ' スクリプトの上部。これにより、接続内のすべてのステートメントが(または、前述のsetステートメントがオフになるまで)実行されず、代わりに解析/コンパイルのみが実行されます。

  4. コメントブロックを使用して、スクリプト全体をコメントアウトします(つまり、/ *および* /)

編集:「return」ステートメントがバッチ固有であることのデモンストレーション-リターン後も引き続き結果セットが表示されることに注意してください。

select 1
return
go
select 2
return
select 3
go
select 4
return
select 5
select 6
go
36
boydc7

スクリプトの先頭に次を単純に追加しないのはなぜですか

PRINT 'INACTIVE SCRIPT'
RETURN
17
Sparky

RETURN/GOの問題を回避するには、RAISERROR ('Oi! Stop!', 20, 1) WITH LOGを先頭に置くことができます。

これにより、 MSDNのRAISERROR に従ってクライアント接続が閉じられます。

非常にbigマイナス面は、重大度20を使用するにはsysadminである必要があるということです。

編集:

Jersey Dudeのコメントに対抗する簡単なデモ...

RAISERROR ('Oi! Stop!', 20, 1)  WITH LOG
SELECT 'Will not run'
GO
SELECT 'Will not run'
GO
SELECT 'Will not run'
GO
14
gbn

重大度20のRAISERRORは、イベントビューアーでエラーとして報告されます。

SET PARSEONLY ONを使用できます。 (またはNOEXEC)。スクリプトの最後でGO SET PARSEONLY OFFを使用します。

SET PARSEONLY ON;
-- statement between here will not run

SELECT 'THIS WILL NOT EXEC';

GO
-- statement below here will run

SET PARSEONLY OFF;

これをTSQLスクリプトとして実行してみてください

SELECT 1
RETURN
SELECT 2
SELECT 3

リターンは実行を終了します。

RETURN(Transact-SQL)

クエリまたはプロシージャから無条件に終了します。 RETURNは即時かつ完全であり、プロシージャ、バッチ、またはステートメントブロックを終了するためにいつでも使用できます。 RETURNに続くステートメントは実行されません。

3
Adriaan Stander

「グローバル」変数を使用して、GOバッチで機能する、やや気味の悪い方法を次に示します。

if object_id('tempdb..#vars') is not null
begin
  drop table #vars
end

create table #vars (continueScript bit)
set nocount on
  insert #vars values (1)
set nocount off

-- Start of first batch
if ((select continueScript from #vars)=1) begin

  print '1'

  -- Conditionally terminate entire script
  if (1=1) begin
    set nocount on
      update #vars set continueScript=0
    set nocount off
    return
  end

end
go

-- Start of second batch
if ((select continueScript from #vars)=1) begin

  print '2'

end
go

そして、各GOバッチのトランザクションとtry/catchブロックで使用されるのと同じ考え方です。さまざまな条件を変更したり、エラーを生成(0で除算、コメントを参照)して、動作をテストすることができます。

if object_id('tempdb..#vars') is not null
begin
  drop table #vars
end

create table #vars (continueScript bit)
set nocount on
  insert #vars values (1)
set nocount off

begin transaction;
  -- Batch 1 starts here
  if ((select continueScript from #vars)=1) begin
    begin try 
      print 'batch 1 starts'

      if (1=0) begin
        print 'Script is terminating because of special condition 1.'
        set nocount on
          update #vars set continueScript=0
        set nocount off
        return
      end

      print 'batch 1 in the middle of its progress'

      if (1=0) begin
        print 'Script is terminating because of special condition 2.'
        set nocount on
          update #vars set continueScript=0
        set nocount off
        return
      end

      set nocount on
        -- use 1/0 to generate an exception here
        select 1/1 as test
      set nocount off

    end try
    begin catch
      set nocount on
        select 
          error_number() as errornumber
          ,error_severity() as errorseverity
          ,error_state() as errorstate
          ,error_procedure() as errorprocedure
          ,error_line() as errorline
          ,error_message() as errormessage;
        print 'Script is terminating because of error.'
        update #vars set continueScript=0
      set nocount off
      return
    end catch;

  end
  go

  -- Batch 2 starts here
  if ((select continueScript from #vars)=1) begin

    begin try 
      print 'batch 2 starts'

      if (1=0) begin
        print 'Script is terminating because of special condition 1.'
        set nocount on
          update #vars set continueScript=0
        set nocount off
        return
      end

      print 'batch 2 in the middle of its progress'

      if (1=0) begin
        print 'Script is terminating because of special condition 2.'
        set nocount on
          update #vars set continueScript=0
        set nocount off
        return
      end

      set nocount on
        -- use 1/0 to generate an exception here
        select 1/1 as test
      set nocount off

    end try
    begin catch
      set nocount on
        select 
          error_number() as errornumber
          ,error_severity() as errorseverity
          ,error_state() as errorstate
          ,error_procedure() as errorprocedure
          ,error_line() as errorline
          ,error_message() as errormessage;
        print 'Script is terminating because of error.'
        update #vars set continueScript=0
      set nocount off
      return
    end catch;

  end
  go

if @@trancount > 0 begin
  if ((select continueScript from #vars)=1) begin
    commit transaction
    print 'transaction committed'
  end else begin
    rollback transaction;
    print 'transaction rolled back'
  end
end
3
Magnus

非常に明示的かつ強制的な説明にもかかわらず、RETURNはストアドプロシージャ内では機能しませんでした(さらに実行をスキップするため)。条件ロジックを変更する必要がありました。 SQL 2008、2008 R2の両方で発生します:

create proc dbo.prSess_Ins
(
    @sSessID    varchar( 32 )
,   @idSess     int out
)
as
begin
    set nocount on

    select  @id=    idSess
        from    tbSess
        where   sSessID = @sSessID

    if  @idSess > 0 return  -- exit sproc here

    begin   tran
        insert  tbSess  ( sSessID ) values  ( @sSessID )
        select  @idSess=    scope_identity( )
    commit
end

次のように変更する必要がありました。

    if  @idSess is null
    begin
        begin   tran
            insert  tbSess  ( sSessID ) values  ( @sSessID )
            select  @idSess=    scope_identity( )
        commit
    end

重複した行を見つけた結果として発見されました。 PRINTのデバッグにより、IFチェックで@idSessの値がゼロよりも大きいことが確認されました-RETURNは実行を中断しませんでした!

2
Astrogator

私は質問が古く、いくつかの異なる方法で正しく答えられたことを知っていますが、私が同じような状況で使用した私の答えはありません。最初のアプローチ(非常に基本的な):

IF (1=0)
BEGIN
    PRINT 'it will not go there'
    -- your script here
END
PRINT 'but it will here'

2番目のアプローチ:

PRINT 'stop here'
RETURN
    -- your script here
PRINT 'it will not go there'

自分で簡単にテストして、期待どおりに動作することを確認できます。

1
Pawel Czapski