【发布时间】:2011-01-02 22:32:55
【问题描述】:
Microsoft SQL Server T-SQL 中是否有命令告诉脚本停止处理? 我有一个脚本想保留用于存档,但我不想让任何人运行它。
【问题讨论】:
标签: sql sql-server tsql sql-scripts
Microsoft SQL Server T-SQL 中是否有命令告诉脚本停止处理? 我有一个脚本想保留用于存档,但我不想让任何人运行它。
【问题讨论】:
标签: sql sql-server tsql sql-scripts
另一种解决方案是使用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 语句之前,我建议你阅读他在Flow control in T-SQL Scripts 上的教程。
【讨论】:
我知道这个问题很老,并且以几种不同的方式得到了正确的回答,但没有我在类似情况下使用过的答案。 第一种方法(非常基本):
IF (1=0)
BEGIN
PRINT 'it will not go there'
-- your script here
END
PRINT 'but it will here'
第二种方法:
PRINT 'stop here'
RETURN
-- your script here
PRINT 'it will not go there'
您可以自己轻松地对其进行测试,以确保其行为符合预期。
【讨论】:
通过使用“全局”变量,这是一种适用于 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-batch 的事务和 try/catch 块的相同想法。您可以尝试更改各种条件和/或让它产生错误(除以 0,参见 cmets)来测试它的行为:
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
【讨论】:
严重性为 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;
【讨论】:
尽管它的描述非常明确和有力,但 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 确认 @idSess 在 IF 检查中的值大于零 - RETURN 没有中断执行!
【讨论】:
return 1),RETURN会按预期工作——退出sproc。
要解决 RETURN/GO 问题,您可以将 RAISERROR ('Oi! Stop!', 20, 1) WITH LOG 放在顶部。
这将按照RAISERROR on MSDN关闭客户端连接。
非常大的缺点是您必须是系统管理员才能使用严重性 20。
编辑:
反驳 Jersey Dude 评论的简单演示......
RAISERROR ('Oi! Stop!', 20, 1) WITH LOG
SELECT 'Will not run'
GO
SELECT 'Will not run'
GO
SELECT 'Will not run'
GO
【讨论】:
不,没有 - 您有两种选择:
将整个脚本包装在一个大的 if/end 块中,该块被简单地确保为不正确(即“如果 1=2 开始” - 这仅在脚本不包含任何 GO 语句时才有效(因为那些表示新批次)
在顶部使用 return 语句(同样,受批处理分隔符的限制)
使用基于连接的方法,这将确保整个脚本不执行(更准确地说是整个连接) - 在脚本顶部使用 'SET PARSEONLY ON' 或 'SET NOEXEC ON' 之类的东西。这将确保连接中的所有语句(或直到所述 set 语句被关闭)不会执行,而只会被解析/编译。
使用注释块注释掉整个脚本(即 /* 和 */)
编辑:证明“return”语句是特定于批次的 - 请注意,在返回后您将继续看到结果集:
select 1
return
go
select 2
return
select 3
go
select 4
return
select 5
select 6
go
【讨论】:
尝试将其作为 TSQL 脚本运行
SELECT 1
RETURN
SELECT 2
SELECT 3
return 结束执行。
无条件退出查询或 程序。 RETURN 是立即的,并且 完整,可随时使用 退出程序、批次或 语句块。声明 follow RETURN 不会被执行。
【讨论】:
为什么不简单地将以下内容添加到脚本的开头
PRINT 'INACTIVE SCRIPT'
RETURN
【讨论】: