Can I print immediately for each iteration in a loop?

亡梦爱人 提交于 2019-12-09 00:18:08

问题


My deployment server runs a deployment script for every new database build.

Part of the script blocks to wait for another asynchronous operation to complete.

The blocking code looks like this:

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;

It uses the WITH NOWAIT clause of RAISERROR instead of PRINT because it's supposed to print a status update for every iteration.

The deployment server runs the script in sqlcmd with this command:

sqlcmd.exe -i print_test.sql

The output appears all at once like this:

status is 1
status is 2
status is 3
status is 4
status is 5

It should print this after one second:

status is 1

After another second it should print this

status is 2

And so on.

Is there a way to do this in sqlcmd?


回答1:


Is there a way to do this in sqlcmd?

Not as far as I know.

It has already been reported on Connect. See RAISERROR WITH NOWAIT not honoured in SQLCMD11

SQLCMD was rewritten in SQL 2012 to use ODBC. Here is a small regression error that appears to have sneaked in. If you a script which uses RAISERROR WITH NOWAIT, the output is nevertheless buffered. This works correctly with OSQL and SQLCMD from SQL 2008.

but is currently not fixed.

I suppose you could add a SELECT in there of your network packet size (or increase the existing message size) to flush the buffer as a workaround.

For example

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; 



回答2:


You can use osql instead. It's deprecated, but it works as you expect.

The equivalent command is:

osql -E -n -i print_test.sql

osql by default expects a username and password. Use the -E switch to use Windows authentication. This is the opposite of sqlcmd default behavior.

osql by default prints a number for every line in the input file script.

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

Use the -n switch to suppress the line numbers.

sqlcmd has no -n switch. It just doesn't print line numbers when the -i switch is set.

Martin Smith led me to the workaround by quoting the Microsoft Connect item about this issue.

If you a script which uses RAISERROR WITH NOWAIT, the output is nevertheless buffered. This works correctly with OSQL and SQLCMD from SQL 2008.




回答3:


I was having this issue also and preliminarily (using your example) it would seem that the powershell cmdlet invoke-sqlcmd doesn't have this same issue.

So if you can switch your deploy server to calling a powershell script instead, this may be an option.

However there are some limitations of invoke-sqlcmd compared with sqlcmd so check the docs. http://msdn.microsoft.com/en-us/library/cc281720.aspx. Your mileage may vary.

Using powershell may also simplify the sqlcmdvariable supplying method which is a bit troublesome.. although typically I've now solved that so I'm off to break it all again.



来源:https://stackoverflow.com/questions/20608989/can-i-print-immediately-for-each-iteration-in-a-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!