71

Is there a command in Microsoft SQL Server T-SQL to tell the script to stop processing? I have a script that I want to keep for archival purposes, but I don't want anyone to run it.

2

10 Answers 10

67

An alternate solution could be to alter the flow of execution of your script by using the GOTO statement...

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!

Warning! The above sample was derived from an example I got from Merrill Aldrich. Before you implement the GOTO statement blindly, I recommend you read his tutorial on Flow control in T-SQL Scripts.

5
  • 1
    Thank you Jed! I like his :ON Error EXIT example. Commented Apr 4, 2012 at 18:45
  • 12
    @Pedro: This will fail if you add GO between the working script sections because GOT applies per batch. You must have GO to break the script into batches when you have CREATE statements etc that often must be the first command in a batch. See chadhoc's comments on other answers
    – gbn
    Commented Apr 5, 2012 at 6:51
  • 1
    Jed. Thanks for the link to "Flow control" what an eye-opener: I've spent the last hour playing with every configuration I can think of and crying at the thought of how many scripts I might need to correct. :-( Commented Nov 29, 2013 at 12:19
  • +1 for the elegant goto and error handling solution. Would have been a little more clear if you had started with "There is no way to just stop."
    – Praesagus
    Commented Jul 16, 2016 at 23:58
  • Does not work if you have any GO statements in the skript. Plus GOTO is never a good programming style and should not be used!
    – webMac
    Commented Feb 1, 2017 at 12:27
42

No, there isn't one - you have a couple of options:

  1. Wrap the whole script in a big if/end block that is simply ensured to not be true (i.e. "if 1=2 begin" - this will only work however if the script doesn't include any GO statements (as those indicate a new batch)

  2. Use the return statement at the top (again, limited by the batch separators)

  3. Use a connection based approach, which will ensure non-execution for the entire script (entire connection to be more accurate) - use something like a 'SET PARSEONLY ON' or 'SET NOEXEC ON' at the top of the script. This will ensure all statements in the connection (or until said set statement is turned off) will not execute and will instead be parsed/compiled only.

  4. Use a comment block to comment out the entire script (i.e. /* and */)

EDIT: Demonstration that the 'return' statement is batch specific - note that you will continue to see result-sets after the returns:

select 1
return
go
select 2
return
select 3
go
select 4
return
select 5
select 6
go
3
  • 2
    I am just genuinely stunned there isn't a command to stop execution. Just... wow.
    – Jacob FW
    Commented Jan 15, 2021 at 21:15
  • 3
    @JacobFW - Please see Erland Somerskog's excellent summary: "Every once in a while, I get the feeling that SQL Server is intentionally designed to be as confusing as possible. When they plan for a new release they ask each other what can we do this time to confuse the users? Sometimes they run a little out of ideas, but then someone says Let's do something with error handling!" (Erland has been a SQL Server MVP for at least 20 years) Commented Jan 20, 2021 at 14:21
  • 1
    @JacobFW - Or Erland's comment on this MS forum about error handling: "Microsoft is guilty of a criminal design". I guess only he can get away with it 😄 (although many of us agree) Commented Jan 20, 2021 at 14:25
22

Why not simply add the following to the beginning of the script

PRINT 'INACTIVE SCRIPT'
RETURN
3
  • 16
    Note that this will not work if the script contains batch separators (i.e. GO statements) - the return will only return from the first batch.
    – boydc7
    Commented Jan 8, 2010 at 14:17
  • 1
    OH! That's good to know! Maybe I should put a /* at the beginning and a */ at the end! Commented Jan 8, 2010 at 14:19
  • Good point chadHoc, I thought he was referring to a stored procedure... Thanks
    – Sparky
    Commented Jan 8, 2010 at 14:24
19

To work around the RETURN/GO issue you could put RAISERROR ('Oi! Stop!', 20, 1) WITH LOG at the top.

This will close the client connection as per RAISERROR on MSDN.

The very big downside is you have to be sysadmin to use severity 20.

Edit:

A simple demonstration to counter Jersey Dude's comment...

RAISERROR ('Oi! Stop!', 20, 1)  WITH LOG
SELECT 'Will not run'
GO
SELECT 'Will not run'
GO
SELECT 'Will not run'
GO
5
  • Again, this will only work in the current batch. Execution begins again at the beginning of the next batch (After the GO). Commented Feb 26, 2011 at 0:00
  • @Jersey Dude: You are wrong. The client connection is closed with severity 20 and above. So no more batches will run. Or can you prove otherwise?
    – gbn
    Commented Feb 26, 2011 at 7:54
  • 1
    @gbn: no, I was wrong. It is Try/Cacth that was introduced in 2005. Sorry.
    – neves
    Commented Jan 29, 2012 at 20:00
  • Thanks for providing the demonstration script, gbn! It executed exactly as you indicated - printed out the error message (Oi! Stop!) and stopped execution! To the naysayers out there - try it, you'll like it! Commented Dec 16, 2015 at 21:16
  • @gbn: You may be right but severity level 20 is problematic for us because "Severity levels from 19 through 25 can only be specified by members of the sysadmin fixed server role or users with ALTER TRACE permissions." Too bad for us. :) Commented Sep 1, 2016 at 21:51
10

RAISERROR with severity 20 will report as error in Event Viewer.

You can use SET PARSEONLY ON; (or NOEXEC). At the end of script use 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;
1
  • Warning : I have just tested SET PARSEONLY ON; around some "EXECUTE sp_something" calls, it does not raise any error but I can say that the procedure is still called and processed !
    – AFract
    Commented Dec 28, 2018 at 10:42
5

Here is a somewhat kludgy way to do it that works with GO-batches, by using a "global" variable.

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

And here is the same idea used with a transaction and a try/catch block for each GO-batch. You can try to change the various conditions and/or let it generate an error (divide by 0, see comments) to test how it behaves:

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
4

Try running this as a TSQL Script

SELECT 1
RETURN
SELECT 2
SELECT 3

The return ends the execution.

RETURN (Transact-SQL)

Exits unconditionally from a query or procedure. RETURN is immediate and complete and can be used at any point to exit from a procedure, batch, or statement block. Statements that follow RETURN are not executed.

1
  • 2
    Again, wouldn't help for a script that contains batch separators (i.e. GO statements) - return is batch specific.
    – boydc7
    Commented Jan 8, 2010 at 14:21
3

Despite its very explicit and forceful description, RETURN did not work for me inside a stored procedure (to skip further execution). I had to modify the condition logic. Happens on both 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

had to be changed into:

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

Discovered as a result of finding duplicated rows. Debugging PRINTs confirmed that @idSess had value greater than zero in the IF check - RETURN did not break execution!

1
  • 2
    Later found that if i specify a return value (as in return 1), RETURN works as expected - exiting the sproc.
    – Astrogator
    Commented Dec 13, 2011 at 16:20
3

I know the question is old and was answered correctly in few different ways but there is no answer as mine which I have used in similar situations. First approach (very basic):

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

Second approach:

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

You can test it easily by yourself to make sure it behave as expected.

0
1

just use SET NOEXEC ON when you want to stop execution.

 Go
 Select 'I want to kill the job after some error or based on some validation.
 Go
 Select 'Raiserror not working'
  Go
 Select 'I have to be admin to define severity 20'
 go
Select 'I got an error, come custom validation failed, I don't want to run the 
 rest  of the script'.
Go
 SET NOEXEC ON
 Select 'rest of the script should not run after NOEXEC on executed'.
1
  • This works great (without raising error etc.). Just remember if you need to re-run statements within the same user session, then you'll need to turn it back OFF, e.g.: SET NOEXEC OFF Commented Mar 20, 2023 at 16:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.