Ho un codice che è:
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)
La lunghezza dello script è di circa 10.000 caratteri e dal momento che sto usando la dichiarazione di stampa che può contenere solo un massimo di 8000. Quindi sto usando due dichiarazioni di stampa.
Il problema è quando ho uno script che è di dire 18000 caratteri, quindi ho usato 3 dichiarazioni di stampa.
Quindi c'è un modo per impostare il numero di istruzioni di stampa a seconda della lunghezza dello script?
È possibile eseguire un ciclo WHILE
in base al conteggio della lunghezza dello script diviso per 8000.
PER ESEMPIO:
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
So che è una vecchia domanda, ma quello che ho fatto non è menzionato qui.
Per me ha funzionato.
DECLARE @info NVARCHAR(MAX)
--SET @info to something big
PRINT CAST(@info AS NTEXT)
La seguente soluzione alternativa non utilizza l'istruzione PRINT
. Funziona bene in combinazione con SQL Server Management Studio.
SELECT CAST('<root><![CDATA[' + @MyLongString + ']]></root>' AS XML)
È possibile fare clic sul XML restituito per espanderlo nel visualizzatore XML incorporato.
C'è un limite lato client abbastanza generoso per le dimensioni visualizzate. Vai a Tools/Options/Query Results/SQL Server/Results to Grid/XML data
per regolarlo se necessario.
Ecco come dovrebbe essere fatto:
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, @[email protected], LEN(@String))
END /*End While loop*/
È venuto attraverso questa domanda e voleva qualcosa di più semplice ... Prova la seguente:
SELECT [processing-instruction(x)][email protected] FOR XML PATH(''),TYPE
Questo proc stampa correttamente il parametro VARCHAR(MAX)
considerando il wrapping:
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
Stavo cercando di utilizzare l'istruzione print per eseguire il debug di alcuni sql dinamici, come immagino che la maggior parte di voi stia utilizzando la stampa per motivi simili.
Ho provato alcune delle soluzioni elencate e ho trovato che la soluzione di Kelsey funziona con tweek minori (@sql è il mio @ script) n.b. LENGTH non è una funzione valida:
--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)
Questo codice fa come commentato aggiungere una nuova riga nell'output, ma per il debug questo non è un problema per me.
La soluzione di Ben B è perfetta ed è la più elegante, anche se per il debugging ci sono un sacco di righe di codice, quindi ho scelto di utilizzare la mia leggera modifica di Kelsey's. Potrebbe valere la pena creare un sistema come stored procedure in msdb per il codice di Ben B che potrebbe essere riutilizzato e chiamato in una riga?
Il codice di Alfoks non funziona purtroppo perché sarebbe stato più semplice.
create la procedura dbo.PrintMax @text nvarchar (max) as begin dichiarare @i int, @newline nchar (2), @print varchar (max); set @newline = nchar (13) + nchar (10); selezionare @i = charindex (@newline, @text); while (@i> 0) inizio selezionare @print = sottostringa (@ testo, 0, @ i); while (len (@print)> 8000) inizio stampa sottostringa (@ print, 0,8000); selezionare @print = substring (@ print, 8000, len (@print)); fine print @print; selezionare @text = substring (@ text, @ i + 2, len (@text)); selezionare @i = charindex (@newline, @text); fine print @text; end
Puoi usare questo
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
Utilizza i feed e gli spazi delle linee come un buon punto di interruzione:
declare @sqlAll as nvarchar(max)
set @sqlAll = '-- Insert all your sql here'
print '@sqlAll - truncated over 4000'
print @sqlAll
print ' '
print ' '
print ' '
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,@[email protected],1) <> ' ' and Substring(@sqlAll,@[email protected],1) <> @newline
BEGIN
set @nextspace = @nextspace + 1
end
print Substring(@sqlAll,@i,[email protected])
set @i = @[email protected]
set @nextspace = 0
end
print ' '
print ' '
print ' '
C'è una grande funzione chiamata PrintMax scritta da Bennett Dill.
Ecco una versione leggermente modificata che utilizza la stored procedure temporanea per evitare la "polution dello schema" (idea da 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;');
MODIFICARE:
Usando CREATE OR ALTER
potremmo evitare due chiamate 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;');
Se il codice sorgente non presenterà problemi con LF da sostituire con CRLF, non è richiesto alcun debug seguendo i semplici output dei codici.
--http://stackoverflow.com/questions/7850477/how-to-print-varcharmax-using-print-statement
--Bill Bai
SET @SQL=replace(@SQL,char(10),char(13)+char(10))
SET @SQL=replace(@SQL,char(13)+char(13)+char(10),char(13)+char(10) )
DECLARE @Position int
WHILE Len(@SQL)>0
BEGIN
SET @Position=charindex(char(10),@SQL)
PRINT left(@SQL,@Position-2)
SET @SQL=substring(@SQL,@Position+1,len(@SQL))
end;
O semplicemente:
PRINT SUBSTRING(@SQL_InsertQuery, 1, 8000)
PRINT SUBSTRING(@SQL_InsertQuery, 8001, 16000)
Questo dovrebbe funzionare correttamente questo è solo un miglioramento delle risposte precedenti.
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
Ecco un'altra versione. Questo estrae ciascuna sottostringa per stampare dalla stringa principale invece di ridurre la stringa principale di 4000 su ciascun ciclo (che potrebbe creare un sacco di stringhe molto lunghe sotto il cofano - non è sicuro).
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