Як я змиваю буфер PRINT у TSQL?


220

У мене дуже довго працює збережена процедура в SQL Server 2005, яку я намагаюся налагодити, і для цього використовую команду 'print'. Проблема полягає в тому, що я повертаю повідомлення з SQL Server лише в самому кінці парока - я хотів би мати змогу очистити буфер повідомлень і побачити ці повідомлення одразу під час виконання парока, а не в самому кінці кінець.


1
Лише коротке повідомлення для людей, які (як і я) вважають, що відповіді на них не працюють: обов’язково перейдіть на вкладку "Повідомлення", коли запит працює. За замовчуванням ви побачите вкладку "Результати".
Томаш

Відповіді:


305

Використовуйте RAISERRORфункцію:

RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT

Ви не повинні повністю замінювати всі ваші відбитки на рейнджер. Якщо у вас є цикл або великий курсор десь, просто зробіть це один-два рази за ітерацію або навіть просто кожні кілька ітерацій.

Також: Я вперше дізнався про RAISERROR за цим посиланням, яке зараз вважаю остаточним джерелом обробки помилок на SQL Server і, безумовно, варто прочитати його:
http://www.sommarskog.se/error-handling-I.html


41
Зауважте, що TRY / CATCH у SQL буде вловлювати помилки лише з суворістю> 10, тому використання RAISERROR таким чином не перескочить у ваш оператор CATCH. Що чудово, адже це означає, що ви все ще можете використовувати RAISERROR, як цей, з TRY / CATCH. ref: msdn.microsoft.com/en-us/library/ms175976.aspx
Рорі

13
Зауважте, що це не працює після перших 500 повідомлень; як тільки ви надрукуєте більше, це раптом починає буферизацію!
GendoIkari

@MahmoudMoravej Ні, я все ще запускаю тривалі процеси, що використовують RAISEERROR, і я просто маю справу з тим, що через деякий час повідомлення починають завантажуватися. Здається, єдиним рішенням було б використовувати інший інструмент, відмінний від SSMS.
GendoIkari

1
Я думаю, що це щось, що змінилося в останній версії SS. Зрештою, коли я вперше написав це, ми використовували RAISERROR для широкого журналу пакетних процесів за ніч з багатьма більш ніж 500 повідомленнями, і це не було проблемою. Але багато що може змінитися за 7 років.
Джоел Куехорн

1
За повідомленням @ GendoIkari. Я спробував це з ssms з 2016SP1 з цим сценарієм. У 500 він переходить на буферизацію 50 ліній, а в 1 к переходить на 100 ліній кожна. Це тривало принаймні до 2k, але тоді я припинив сценарій. оголосити @i int set @i = 0 оголосити @t varchar (100), а 1 = 1 почати встановлювати @i = @i + 1 набір @t = 'друкувати' + перетворити (varchar, @i) RAISERROR (@t, 10 , 1) З НЕЧАСКОЮ затримку очікування '00: 00: 00.010 'кінець
Зартаг

28

Спираючись на відповідь @JoelCoehoorn, мій підхід полягає в тому, щоб залишити всі мої твердження PRINT на місці і просто дотримуватися їх із заявою RAISERROR, щоб викликати спалах.

Наприклад:

PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT

Перевага такого підходу полягає в тому, що оператори PRINT можуть об'єднувати рядки, тоді як RAISERROR не може. (Таким чином, у будь-якому випадку у вас однакова кількість рядків коду, як і вам потрібно було б оголосити та встановити змінну для використання в RAISERROR).

Якщо ви, як і я, використовуєте AutoHotKey або SSMSBoost або подібний інструмент, ви можете легко встановити ярлик, наприклад "] flush", щоб ввести для вас лінію RAISERROR. Це економить ваш час, якщо це кожен раз однаковий рядок коду, тобто його не потрібно налаштовувати на вміст певного тексту чи змінної.


6
Зауважте, що RAISERROR()підтримує printf()інтерполяцію в рядковому стилі. Наприклад, якщо @MyVariableNameтип stringish (наприклад, VARCHAR(MAX), NVARCHAR(MAX)і т.д.), ви можете використовувати RAISERROR()з одним рядком: RAISERROR(N'MyVariableName: %s', 0, 1, @MyVariableName).
бінкі

Це так зручно! Я знаю, що RAISERROR може зробити просту заміну, але спробуйте замінити час [дата] або викликати функцію всередині оператора RAISERROR! Ця відповідь дає простий ФЛУШ у вигляді підняття порожньої помилки (ціною нового рядка).
Томаш

19

Так ... Перший параметр функції RAISERROR потребує змінної NVARCHAR. Тому спробуйте наступне;

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

АБО

RAISERROR (n'Here''s your message...', 0, 1) WITH NOWAIT

10
Перегляньте вкладку Повідомлення внизу, поруч із вкладкою Результати або перейдіть до режиму Результати до тексту.
Мехмет Ергут

Щоб переключитися на Результати в текстовий режим, в SSMS, меню Інструменти -> Параметри -> Результати запитів -> SQL Server -> Загальне -> Призначення за замовчуванням для результатів і виберіть "Результати до тексту" замість "Результати до сітки", повторно -відкрийте вікно запиту, і тоді ви не будете сидіти там, дивлячись на порожню вкладку "Результати", як манекен, а вихід RAISERROR переходить на вкладку "Повідомлення".
Адам

12

Ще одним кращим варіантом є не залежати від PRINT або RAISERROR, а просто завантажувати ваші "друковані" заяви у таблицю №# Temp в TempDB або в постійну таблицю у вашій базі даних, яка надасть вам доступ до даних негайно через оператор SELECT з іншого вікна . Це працює найкраще для мене. Використання постійної таблиці також служить журналом до того, що відбувалося в минулому. Виписки щодо друку зручні для помилок, але, використовуючи таблицю журналів, ви також можете визначити точну точку відмови на основі останнього зафіксованого значення для цього конкретного виконання (якщо ви відстежуєте загальний час початку виконання у вашій таблиці журналу.)


2
Це може бути проблемою, якщо ви пишете справді транзакційний сценарій з фіксацією та відкатом. Я не вірю, що вам вдасться запитати живу таблицю темп - і вона піде, якщо транзакція не вдасться.
SteveJ

@SteveJ ви можете запитати його наживо, використовуючи SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;у своєму сеансі моніторингу
TheConstructor

1
@TheConstructor; Це корисна порада - я скористаюся цим, дякую. Однак, хіба ми все ще не залишилися з тимчасовою таблицею, яка відходить на відкат? Якщо робити аналіз відмов, здається, це був би великий недолік.
SteveJ

1
@SteveJ так, це, безумовно, є. Звичайно, ви можете скопіювати дані в READ UNCOMMITTEDтранзакції в іншу таблицю, але ви, мабуть, пропустите момент безпосередньо раніше ROLLBACK. Тож це, мабуть, вирішує "як далеко?" не "чому відкат?"
TheConstructor

4

Тільки для довідки, якщо ви працюєте в скриптах (пакетна обробка), а не в збереженій процедурі , вимикання виводу запускається командою GO, наприклад

print 'test'
print 'test'
go

Загалом, мій висновок такий: висновок виконання скрипту mssql, що виконується в SMS GUI або з sqlcmd.exe, видається у файл, stdoutput, gui вікно в першому операторі GO або до кінця сценарію.

Промивання всередині збереженої процедури функціонує інакше, оскільки ви не можете розмістити GO всередині.

Довідка: tsql Go оператор


2
goне просто вимикає вихід, він закінчує партію згідно з наданим вами посиланням. Все, що ви declareскажете, відкидається, тому не дуже корисно для налагодження. declare @test int print "I want to read this!" go set @test=5буде, хоча ви помилка, яка стверджує, що @testне визначено, оскільки вона знаходиться в новій партії.
asontu

1
Я погоджуюся, це неправильна відповідь на це питання, але я ставлю відповідь (див. Відмову на початку), оскільки це може бути корисним для когось іншого - наприклад, для когось, хто виконує batch sql.
Роберт Луйо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.