Como imprimir VARCHAR (MAX) usando Print Statement?

Eu tenho um código que é:

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) 

O comprimento do script é de cerca de 10.000 caracteres e desde que eu estou usando declaração de impressão que pode conter apenas max de 8000. Então, eu estou usando duas instruções de impressão.

O problema é quando eu tenho um script que é de 18000 caracteres, então eu usei 3 instruções de impressão.

Então, existe uma maneira que eu poderia definir o número de instruções de impressão, dependendo do comprimento do script?

Você poderia fazer um loop WHILE base na contagem do tamanho do seu script dividido por 8000.

POR EXEMPLO:

 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 

Eu sei que é uma questão antiga, mas o que eu fiz não é mencionado aqui.

Para mim, o seguinte funcionou.

 DECLARE @info NVARCHAR(MAX) --SET @info to something big PRINT CAST(@info AS NTEXT) 

A seguinte solução alternativa não usa a instrução PRINT . Ele funciona bem em combinação com o SQL Server Management Studio.

 SELECT CAST('' AS XML) 

Você pode clicar no XML retornado para expandi-lo no visualizador XML integrado.

Há um limite muito generoso do lado do cliente no tamanho exibido. Vá para Tools/Options/Query Results/SQL Server/Results to Grid/XML data para ajustá-lo, se necessário.

Aqui está como isso deve ser feito:

 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*/ 

Retirado de http://ask.sqlservercentral.com/questions/3102/any-way-around-the-print-limit-of-nvarcharmax-in-s.html

Veio através desta questão e queria algo mais simples … Tente o seguinte:

 SELECT [processing-instruction(x)]=@Script FOR XML PATH(''),TYPE 

Eu estava olhando para usar a instrução print para depurar alguns sql dynamic como eu imaginaria que a maioria de vocês está usando a impressão por razões semelhantes.

Eu tentei algumas das soluções listadas e descobri que a solução de Kelsey funciona com pequenas modificações (@sql é meu @script) nb LENGTH não é uma function válida:

 --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) 

Este código faz como comentado adicionar uma nova linha na saída, mas para depurar isso não é um problema para mim.

A solução de Ben B é perfeita e é a mais elegante, embora para a debugging haja muitas linhas de código, então escolho usar minha pequena modificação de Kelsey. Pode valer a pena criar um sistema como o procedimento armazenado em msdb para o código do Ben B, que poderia ser reutilizado e chamado em uma linha?

O código de Alfoks não funciona, infelizmente, porque isso teria sido mais fácil.

Este proc imprime corretamente o parâmetro VARCHAR(MAX) considerando o acondicionamento:

 CREATE PROCEDURE [dbo].[Print] @sql varchar(max) AS BEGIN declare @n int, @i int = 0, @s int = 0, -- substring start posotion @l int; -- substring length set @n = ceiling(len(@sql) / 8000.0); while @i < @n begin set @l = 8000 - charindex(char(13), reverse(substring(@sql, @s, 8000))); print substring(@sql, @s, @l); set @i = @i + 1; set @s = @s + @l + 2; -- accumulation + CR/LF end return 0 END 
 criar procedimento dbo.PrintMax @text nvarchar (max)
 Como
 início
     declare @i int, @newline nchar (2), @print varchar (max); 
     conjunto @newline = nchar (13) + nchar (10);
     selecione @i = charindex (@newline, @text);
     enquanto (@i> 0)
     início
         selecione @print = substring (@ text, 0, @i);
         while (len (@print)> 8000)
         início
             substring de impressão (@ print, 0,8000);
             selecione @print = substring (@ print, 8000, len (@print));
         fim
         print @print;
         select @text = substring (@ texto, @ i + 2, len (@texto));
         selecione @i = charindex (@newline, @text);
     fim
     print @text;
 fim

Você pode usar isso

 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 

Usa Line Feeds e espaços como um bom ponto de interrupção:

declare @sqlAll como nvarchar (max) set @sqlAll = ‘- Insira todo o seu sql aqui

‘print’ @sqlAll – truncado acima de 4000 ‘print @sqlTudo imprimir’ ‘imprimir’ ‘imprimir’ ‘

  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 ' ' 

Existe uma grande function chamada PrintMax, escrita por Bennett Dill .

Aqui está uma versão ligeiramente modificada que usa o procedimento armazenado temp para evitar a “poluição do esquema” (idéia de 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;'); 

DBFiddle Demo

Aqui está outra versão. Este extrai cada substring para imprimir a string principal em vez de reduzir a string principal em 4000 em cada loop (o que pode criar muitas strings muito longas sob o capô – não tenho certeza).

 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 

Isso deve funcionar corretamente, isso é apenas uma melhoria das respostas anteriores.

 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