Можно ли печатать сразу для каждой итерации в цикле?

Мой сервер развертывания запускает сценарий развертывания для каждой новой сборки базы данных.

Часть скрипта блокирует ожидание завершения другой асинхронной операции.

Код блокировки выглядит следующим образом:

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;

Он использует WITH NOWAIT пункт о RAISERROR вместо PRINT потому что он должен печатать обновление статуса для каждой итерации.

Сервер развертывания запускает сценарий в sqlcmd с помощью этой команды:

sqlcmd.exe -i print_test.sql

Выходные данные появляются сразу, как это:

статус 1
статус 2
статус 3
статус 4
статус 5

Это должно напечатать это через одну секунду:

статус 1

Еще через секунду он должен напечатать это

статус 2

И так далее.

Есть ли способ сделать это в sqlcmd?

3 ответа

Решение

Вместо этого вы можете использовать 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.

Мартин Смит привел меня к обходному пути, процитировав пункт Microsoft Connect об этой проблеме.

Если вы используете скрипт, который использует RAISERROR WITH NOWAIT, вывод тем не менее буферизуется. Это работает правильно с OSQL и SQLCMD из SQL 2008.

Есть ли способ сделать это в sqlcmd?

Не так далеко, как я знаю.

Об этом уже сообщалось в Connect. Посмотрите, что RAISERROR WITH NOWAIT не соблюдается в SQLCMD11

SQLCMD был переписан в SQL 2012 для использования ODBC. Вот небольшая ошибка регрессии, которая, кажется, проникла внутрь. Если у вас скрипт, который использует RAISERROR WITH NOWAIT, вывод, тем не менее, буферизуется. Это работает правильно с OSQL и SQLCMD из SQL 2008.

но в настоящее время не исправлено.

Я полагаю, вы могли бы добавить 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; 

У меня тоже была эта проблема, и предварительно (на вашем примере) может показаться, что у командлета powershell invoke-sqlcmd такой же проблемы нет.

Так что, если вы можете вместо этого переключить свой сервер развертывания на вызов сценария powershell, это может быть вариантом.

Однако есть некоторые ограничения invoke-sqlcmd по сравнению с sqlcmd, поэтому проверьте документы. http://msdn.microsoft.com/en-us/library/cc281720.aspx. Ваш пробег может отличаться.

Использование powershell также может упростить метод предоставления sqlcmdvariable, что немного проблематично... хотя обычно я уже решил это, поэтому я собираюсь все это снова сломать.

Другие вопросы по тегам