如何在TSQL中刷新PRINT缓冲区?

Eri*_*bes 213 t-sql sql-server printing

我在SQL Server 2005中有一个非常长时间运行的存储过程,我正在尝试调试,而我正在使用'print'命令来执行此操作.问题是,我只是在我的sproc的最后从SQL Server获取消息 - 我希望能够刷新消息缓冲区并在sproc的运行时立即看到这些消息,而不是在结束.

Joe*_*orn 298

使用RAISERROR功能:

RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT
Run Code Online (Sandbox Code Playgroud)

您不应该用raiserror完全替换所有打印件.如果你有一个循环或大光标,只需每次迭代一次或两次,甚至每次迭代.

另外:我首先在这个链接上了解了RAISERROR,我现在认为它是SQL Server错误处理的权威来源,绝对值得阅读:http:
//www.sommarskog.se/error-handling-I.html

  • 请注意,SQL中的TRY/CATCH只会捕获严重性> 10的错误,因此以这种方式使用RAISERROR不会跳转到CATCH语句中.这很棒,因为这意味着您仍然可以使用TRY/CATCH这样使用RAISERROR.参考:http://msdn.microsoft.com/en-us/library/ms175976.aspx (40认同)
  • 请注意,这在前500条消息之后不起作用; 一旦你打印超过它突然开始缓冲! (12认同)
  • 在@GendoIkari 的通知下。我已经用这个脚本从 2016SP1 开始用 ssms 尝试过它。在 500 时,它切换到缓冲 50 行,而在 1k 时,它切换到每行 100 行。这至少持续到 2k,但后来我停止了脚本。声明@i int set @i = 0 声明@t varchar(100) while 1=1 begin set @i = @i + 1 set @t = 'print ' + convert(varchar, @i) RAISERROR (@t, 10 , 1) WITH NOWAIT waitfor delay '00:00:00.010' end (2认同)

Mik*_*ike 23

在@JoelCoehoorn的答案的基础上,我的方法是保留所有PRINT语句,并简单地用RAISERROR语句跟随它们以引起刷新.

例如:

PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT
Run Code Online (Sandbox Code Playgroud)

这种方法的优点是PRINT语句可以连接字符串,而RAISERROR则不能.(因此,无论哪种方式,您都拥有相同数量的代码行,因为您必须声明并设置要在RAISERROR中使用的变量).

如果像我一样使用AutoHotKey或SSMSBoost或同等工具,您可以轻松设置快捷方式,例如"] flush",为您输入RAISERROR行.如果每次都是相同的代码行,则可以节省您的时间,即不需要自定义以保存特定文本或变量.

  • 请注意,`RAISERROR()`确实支持`printf()`样式的字符串插值。例如,如果@MyVariableName是一种字符串类型(例如VARCHAR(MAX),NVARCHAR(MAX)等),则可以将RAISERROR()与一行一起使用:RAISERROR(N' MyVariableName:%s',0、1,@ MyVariableName)。 (5认同)

tcb*_*zil 17

是...... RAISERROR函数的第一个参数需要一个NVARCHAR变量.所以尝试以下方法;

-- Replace PRINT function
DECLARE @strMsg NVARCHAR(100)
SELECT @strMsg = 'Here''s your message...'
RAISERROR (@strMsg, 0, 1) WITH NOWAIT
Run Code Online (Sandbox Code Playgroud)

要么

RAISERROR (n'Here''s your message...', 0, 1) WITH NOWAIT
Run Code Online (Sandbox Code Playgroud)

  • 查看底部的"消息"选项卡,"结果"选项卡旁边或切换到"结果到文本"模式. (10认同)

小智 11

另一个更好的选择是不依赖于PRINT或RAISERROR,只需将"print"语句加载到TempDB中的## Temp表或数据库中的永久表中,这将通过另一个窗口中的SELECT语句立即显示数据.这对我来说是最好的.使用永久表也可以作为过去发生的事情的日志.print语句对于错误很方便,但是使用日志表还可以根据特定执行的最后记录值确定确切的故障点(假设您跟踪日志表中的总执行开始时间.)

  • 如果您使用提交和回滚编写真正的事务性脚本,这可能是一个问题.我不相信你能够实时查询你的临时表 - 如果你的交易失败,它就会消失. (2认同)
  • @TheConstructor ; 这是一个有用的提示 - 我会利用它,谢谢。但是,在回滚时,我们不是仍然留下临时表吗?如果做失效分析,这似乎是一个很大的缺点。 (2认同)

Rob*_*ujo 5

仅供参考,如果您在脚本(批处理)中工作,而不是在存储过程中,则刷新输出由 GO 命令触发,例如

print 'test'
print 'test'
go
Run Code Online (Sandbox Code Playgroud)

一般来说,我的结论如下:在 SMS GUI 中或使用 sqlcmd.exe 执行的 mssql 脚本执行的输出在第一个 GO 语句或直到脚本结束时刷新到文件、stdoutput、gui 窗口。

存储过程内部的刷新功能不同,因为您不能将 GO 放入其中。

参考:tsql Go语句

  • `go` 不仅刷新输出,还会根据您提供的链接结束批处理。你声明的任何东西都会被丢弃,所以不太适合调试。`declare @test int print "我想读这个!" go set @test=5` 会出现一个错误,声称 `@test` 未定义,因为它在一个新批次中。 (5认同)
  • 我同意,这不是这个问题的正确答案,但我给出了答案(请参阅开头的免责声明),因为它可能对其他人有用 - 例如运行批处理 sql 的人。 (2认同)