【问题标题】:Can I print immediately for each iteration in a loop?我可以为循环中的每次迭代立即打印吗?
【发布时间】:2014-01-03 17:30:52
【问题描述】:

我的部署服务器为每个新的数据库构建运行一个部署脚本。

部分脚本阻塞等待另一个异步操作完成。

阻塞代码如下所示:

DECLARE @i INT = 0;
DECLARE @laststatus NVARCHAR(MAX) = N'';

WHILE @i < 5
BEGIN
  -- the real delay is longer
  WAITFOR DELAY '00:00:01';

  -- poll async operation status here
  SET @i = @i + 1;

  SET @laststatus = N'status is ' + CAST(@i AS NVARCHAR(MAX));
  RAISERROR(@laststatus, 0, 1) WITH NOWAIT;
END;

它使用RAISERRORWITH NOWAIT 子句而不是PRINT,因为它应该为每次迭代打印一个状态更新。

部署服务器使用以下命令在 sqlcmd 中运行脚本:

sqlcmd.exe -i print_test.sql

输出立即显示如下:

状态为 1
状态为 2
状态为 3
状态为 4
状态为 5

它应该在一秒钟后打印:

状态为 1

再过一秒钟,它应该会打印出来

状态为 2

等等。

有没有办法在 sqlcmd 中做到这一点?

【问题讨论】:

  • 对我来说很好。您是否在 SSMS 中运行此程序?如果是这样,您是否在查询开始运行后立即单击消息选项卡?只有在查询停止执行时才会自动设置焦点。
  • 顺便说一句,您也可以在没有中间变量的情况下执行RAISERROR(N'status is %i', 0, 1, @i) WITH NOWAIT;
  • @MartinSmith 你说得对 SSMS。我需要在 sqlcmd 中发生同样的事情。只是注意到他们在这里对我来说表现不同!编辑问题以澄清。

标签: sql-server-2012 sqlcmd


【解决方案1】:

有没有办法在 sqlcmd 中做到这一点?

据我所知没有。

已在 Connect 上报告过。见RAISERROR WITH NOWAIT not honoured in SQLCMD11

SQLCMD 在 SQL 2012 中被重写以使用 ODBC。这里有一个小 似乎已经潜入的回归错误。如果你是一个脚本 它使用 RAISERROR WITH NOWAIT,但输出仍然被缓冲。 这适用于 SQL 2008 中的 OSQL 和 SQLCMD。

但目前尚未修复。

我想您可以在其中添加一个 SELECT 来表示您的网络数据包大小(或增加现有消息大小)以刷新缓冲区作为一种解决方法。

例如

DECLARE @i INT = 0;

WHILE @i < 5
  BEGIN
      -- poll async operation status here
      SET @i = @i + 1;

      PRINT 'status is ' + CAST(@i AS VARCHAR(10)) + SPACE(4000);

      WAITFOR DELAY '00:00:01';
  END; 

【讨论】:

  • 我还没有测试过“解决方法”实际上在sqlcmd 中有效。我想你可以尝试发送越来越多的数据,但它可能只是被编码为在执行完成之前不显示输出。
  • 将输出填充为大于网络数据包大小对我不起作用。用 SELECT 替换 PRINT 也不起作用。看起来 sqlcmd 会缓冲所有数据包,直到批处理结束。不过,osql 可以工作!见my answer
  • “Microsoft 于 2013 年 4 月 24 日 10:48 发布感谢您的反馈!我们将在未来的规划中考虑到这一点”——他们想知道我为什么讨厌他们
  • 似乎 powershell 的 Invoke-SqlCmd 和 osql 一样按预期工作。
【解决方案2】:

您可以改用osql。它已被弃用,但它可以按您的预期工作。

等效的命令是:

osql -E -n -i print_test.sql

默认情况下,osql 需要用户名和密码。使用 -E 开关来使用 Windows 身份验证。这与 sqlcmd 默认行为相反。

osql 默认为输入文件脚本中的每一行打印一个数字。

1> 2> 3> 4> 5> 6> 7> 8> 9> 10> 11> 12> 13> 14> 15>

使用 -n 开关隐藏行号。

sqlcmd 没有 -n 开关。设置 -i 开关时,它只是不打印行号。

Martin Smith 通过引用 Microsoft Connect item 关于此问题的方式引导我找到解决方法。

如果您的脚本使用 RAISERROR WITH NOWAIT,则输出仍然会被缓冲。 这适用于 OSQL 和 SQL 2008 中的 SQLCMD。

【讨论】:

  • 或者另一种解决方法是在sqlcmd 模式下使用SSMS,具体取决于首先想要使用sqlcmd 的动机。
  • @MartinSmith 该脚本旨在在我的部署服务器上运行,由新的数据库构建触发。我可以在这里使用命令行工具。我再次编辑了问题以澄清上下文。谢谢!
  • 我将此标记为已接受,因为它对我有用。以后我会改用 PowerShell。
  • osql 不支持 sqlcmd 参数(替换 sql 文件的位)所以对我没有好处,但无论如何感谢stackoverflow.com/a/3814366/10245
【解决方案3】:

我也遇到了这个问题,并且初步(使用您的示例)似乎 powershell cmdlet invoke-sqlcmd 没有同样的问题。

因此,如果您可以将部署服务器切换为调用 powershell 脚本,这可能是一种选择。

但是,与 sqlcmd 相比,invoke-sqlcmd 存在一些限制,因此请查看文档。 http://msdn.microsoft.com/en-us/library/cc281720.aspx。您的里程可能会有所不同。

使用 powershell 还可以简化 sqlcmdvariable 提供方法,这有点麻烦。虽然通常我现在已经解决了这个问题,所以我要再次打破它。

【讨论】:

  • 你能提供一个PowerShell的例子吗?我的 Invoke-Sqlcmd 版本似乎完全忽略了 PRINT 语句。 Invoke-Sqlcmd -Query "PRINT 'Hello, world!'" 不产生任何输出。
猜你喜欢
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-21
  • 1970-01-01
  • 1970-01-01
  • 2017-04-28
  • 1970-01-01
相关资源
最近更新 更多