问题
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