Как распечатать VARCHAR (MAX)с помощью инструкции Print?
У меня есть код, который выглядит так:
DECLARE @Script VARCHAR(MAX)
SELECT @Script = definition FROM manged.sys.all_sql_modules sq
where sq.object_id = (SELECT object_id from managed.sys.objects
Where type = 'P' and Name = 'usp_gen_data')
Declare @Pos int
SELECT @pos=CHARINDEX(CHAR(13)+CHAR(10),@script,7500)
PRINT SUBSTRING(@Script,1,@Pos)
PRINT SUBSTRING(@script,@pos,8000)
длина скрипта составляет около 10 000 символов, и поскольку я использую оператор print, который может содержать только максимум 8000. Поэтому я использую два оператора печати.
проблема в том, что когда у меня есть скрипт, который имеет, скажем, 18000 символов, то я использовал 3 Инструкции печати.
Так есть ли способ, которым я мог бы установить количество операторов печати в зависимости от длины скрипта?
13 ответов:
вы могли бы сделать
WHILE
цикл, основанный на подсчете длины вашего скрипта, разделенной на 8000.например:
DECLARE @Counter INT SET @Counter = 0 DECLARE @TotalPrints INT SET @TotalPrints = (LEN(@script) / 8000) + 1 WHILE @Counter < @TotalPrints BEGIN -- Do your printing... SET @Counter = @Counter + 1 END
Я знаю, это старый вопрос, но то, что я не упомянул здесь.
для меня сработало следующее.
DECLARE @info NVARCHAR(MAX) --SET @info to something big PRINT CAST(@info AS NTEXT)
следующий обходной путь не использует
SELECT CAST('<root><![CDATA[' + @MyLongString + ']]></root>' AS XML)
вы можете нажать на возвращенный XML, чтобы развернуть его во встроенном средстве просмотра XML.
существует довольно щедрый лимит на стороне клиента на отображаемый размер. Перейти к
Tools/Options/Query Results/SQL Server/Results to Grid/XML data
чтобы настроить его, если это необходимо.
вот как это должно быть сделано:
DECLARE @String NVARCHAR(MAX); DECLARE @CurrentEnd BIGINT; /* track the length of the next substring */ DECLARE @offset tinyint; /*tracks the amount of offset needed */ set @string = replace( replace(@string, char(13) + char(10), char(10)) , char(13), char(10)) WHILE LEN(@String) > 1 BEGIN IF CHARINDEX(CHAR(10), @String) between 1 AND 4000 BEGIN SET @CurrentEnd = CHARINDEX(char(10), @String) -1 set @offset = 2 END ELSE BEGIN SET @CurrentEnd = 4000 set @offset = 1 END PRINT SUBSTRING(@String, 1, @CurrentEnd) set @string = SUBSTRING(@String, @CurrentEnd+@offset, LEN(@String)) END /*End While loop*/
наткнулся на этот вопрос и хотел что-то более простое... Попробуйте следующее:
SELECT [processing-instruction(x)]=@Script FOR XML PATH(''),TYPE
Я хотел использовать инструкцию print для отладки некоторого динамического sql, поскольку я предполагаю, что большинство из вас использует print по аналогичным причинам.
я попробовал несколько из перечисленных решений и обнаружил, что решение Келси работает с незначительными твиками (@sql-это мой @script) n.B. длина не является допустимой функцией:
--http://stackoverflow.com/questions/7850477/how-to-print-varcharmax-using-print-statement --Kelsey DECLARE @Counter INT SET @Counter = 0 DECLARE @TotalPrints INT SET @TotalPrints = (LEN(@sql) / 4000) + 1 WHILE @Counter < @TotalPrints BEGIN PRINT SUBSTRING(@sql, @Counter * 4000, 4000) SET @Counter = @Counter + 1 END PRINT LEN(@sql)
этот код не прокомментировал добавить новую строку в выходной, но для отладки это не проблема для меня.
решение Бена Б идеально и является большинство elegent, хотя для отладки много строк кода, поэтому я решил использовать свою небольшую модификацию Kelsey's. возможно, стоит создать систему, подобную хранимой процедуре в msdb для кода Ben B, который можно повторно использовать и вызывать в одной строке?
код Alfoks не работает, к сожалению, потому что это было бы проще.
create procedure dbo.PrintMax @text nvarchar(max) as begin declare @i int, @newline nchar(2), @print varchar(max); set @newline = nchar(13) + nchar(10); select @i = charindex(@newline, @text); while (@i > 0) begin select @print = substring(@text,0,@i); while (len(@print) > 8000) begin print substring(@print,0,8000); select @print = substring(@print,8000,len(@print)); end print @print; select @text = substring(@text,@i+2,len(@text)); select @i = charindex(@newline, @text); end print @text; end
вы можете использовать этот
declare @i int = 1 while Exists(Select(Substring(@Script,@i,4000))) and (@i < LEN(@Script)) begin print Substring(@Script,@i,4000) set @i = @i+4000 end
использует линейные каналы и пробелы в качестве хорошей точки останова:
объявить @sqlAll как nvarchar(Макс) установите @sqlAll = ' -- вставьте все ваши sql здесь
' печать '@sqlAll-усечено более 4000' print @sqlAll печать ' ' печать ' ' печать ' '
print '@sqlAll - split into chunks' declare @i int = 1, @nextspace int = 0, @newline nchar(2) set @newline = nchar(13) + nchar(10) while Exists(Select(Substring(@sqlAll,@i,3000))) and (@i < LEN(@sqlAll)) begin while Substring(@sqlAll,@i+3000+@nextspace,1) <> ' ' and Substring(@sqlAll,@i+3000+@nextspace,1) <> @newline BEGIN set @nextspace = @nextspace + 1 end print Substring(@sqlAll,@i,3000+@nextspace) set @i = @i+3000+@nextspace set @nextspace = 0 end print ' ' print ' ' print ' '
есть отличная функция под названием PrintMax написано Беннетт Дилл.
вот немного измененная версия, которая использует хранимую процедуру temp, чтобы избежать "загрязнения схемы" (идея от https://github.com/Toolien/sp_GenMerge/blob/master/sp_GenMerge.sql)
EXEC (N'IF EXISTS (SELECT * FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N''tempdb..#PrintMax'') AND type in (N''P'', N''PC'')) DROP PROCEDURE #PrintMax;'); EXEC (N'CREATE PROCEDURE #PrintMax(@iInput NVARCHAR(MAX)) AS BEGIN IF @iInput IS NULL RETURN; DECLARE @ReversedData NVARCHAR(MAX) , @LineBreakIndex INT , @SearchLength INT; SET @SearchLength = 4000; WHILE LEN(@iInput) > @SearchLength BEGIN SET @ReversedData = LEFT(@iInput COLLATE DATABASE_DEFAULT, @SearchLength); SET @ReversedData = REVERSE(@ReversedData COLLATE DATABASE_DEFAULT); SET @LineBreakIndex = CHARINDEX(CHAR(10) + CHAR(13), @ReversedData COLLATE DATABASE_DEFAULT); PRINT LEFT(@iInput, @SearchLength - @LineBreakIndex + 1); SET @iInput = RIGHT(@iInput, LEN(@iInput) - @SearchLength + @LineBreakIndex - 1); END; IF LEN(@iInput) > 0 PRINT @iInput; END;');
EDIT:
используя
CREATE OR ALTER
мы могли бы избежать двух EXEC звонки:EXEC (N'CREATE OR ALTER PROCEDURE #PrintMax(@iInput NVARCHAR(MAX)) AS BEGIN IF @iInput IS NULL RETURN; DECLARE @ReversedData NVARCHAR(MAX) , @LineBreakIndex INT , @SearchLength INT; SET @SearchLength = 4000; WHILE LEN(@iInput) > @SearchLength BEGIN SET @ReversedData = LEFT(@iInput COLLATE DATABASE_DEFAULT, @SearchLength); SET @ReversedData = REVERSE(@ReversedData COLLATE DATABASE_DEFAULT); SET @LineBreakIndex = CHARINDEX(CHAR(10) + CHAR(13), @ReversedData COLLATE DATABASE_DEFAULT); PRINT LEFT(@iInput, @SearchLength - @LineBreakIndex + 1); SET @iInput = RIGHT(@iInput, LEN(@iInput) - @SearchLength + @LineBreakIndex - 1); END; IF LEN(@iInput) > 0 PRINT @iInput; END;');
вот еще одна версия. Этот извлекает каждую подстроку для печати из основной строки вместо того, чтобы уменьшать основную строку на 4000 в каждом цикле (что может создать много очень длинных строк под капотом - не уверен).
CREATE PROCEDURE [Internal].[LongPrint] @msg nvarchar(max) AS BEGIN -- SET NOCOUNT ON reduces network overhead SET NOCOUNT ON; DECLARE @MsgLen int; DECLARE @CurrLineStartIdx int = 1; DECLARE @CurrLineEndIdx int; DECLARE @CurrLineLen int; DECLARE @SkipCount int; -- Normalise line end characters. SET @msg = REPLACE(@msg, char(13) + char(10), char(10)); SET @msg = REPLACE(@msg, char(13), char(10)); -- Store length of the normalised string. SET @MsgLen = LEN(@msg); -- Special case: Empty string. IF @MsgLen = 0 BEGIN PRINT ''; RETURN; END -- Find the end of next substring to print. SET @CurrLineEndIdx = CHARINDEX(CHAR(10), @msg); IF @CurrLineEndIdx BETWEEN 1 AND 4000 BEGIN SET @CurrLineEndIdx = @CurrLineEndIdx - 1 SET @SkipCount = 2; END ELSE BEGIN SET @CurrLineEndIdx = 4000; SET @SkipCount = 1; END -- Loop: Print current substring, identify next substring (a do-while pattern is preferable but TSQL doesn't have one). WHILE @CurrLineStartIdx < @MsgLen BEGIN -- Print substring. PRINT SUBSTRING(@msg, @CurrLineStartIdx, (@CurrLineEndIdx - @CurrLineStartIdx)+1); -- Move to start of next substring. SET @CurrLineStartIdx = @CurrLineEndIdx + @SkipCount; -- Find the end of next substring to print. SET @CurrLineEndIdx = CHARINDEX(CHAR(10), @msg, @CurrLineStartIdx); SET @CurrLineLen = @CurrLineEndIdx - @CurrLineStartIdx; -- Find bounds of next substring to print. IF @CurrLineLen BETWEEN 1 AND 4000 BEGIN SET @CurrLineEndIdx = @CurrLineEndIdx - 1 SET @SkipCount = 2; END ELSE BEGIN SET @CurrLineEndIdx = @CurrLineStartIdx + 4000; SET @SkipCount = 1; END END END
Это должно работать правильно это просто улучшение предыдущих ответов.
DECLARE @Counter INT DECLARE @Counter1 INT SET @Counter = 0 SET @Counter1 = 0 DECLARE @TotalPrints INT SET @TotalPrints = (LEN(@QUERY) / 4000) + 1 print @TotalPrints WHILE @Counter < @TotalPrints BEGIN -- Do your printing... print(substring(@query,@COUNTER1,@COUNTER1+4000)) set @COUNTER1 = @Counter1+4000 SET @Counter = @Counter + 1 END