web-dev-qa-db-fra.com

Comment imprimer VARCHAR (MAX) en utilisant Print Statement?

J'ai un code qui est:

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 longueur du script est d'environ 10 000 caractères. Depuis, j'utilise print statement qui ne peut contenir qu'un maximum de 8 000 caractères. J'utilise donc deux instructions print.

Le problème, c’est quand j’ai un script de 18 000 caractères, puis j’utilisais 3 instructions d’impression.

Donc, est-il possible de définir le nombre d'instructions d'impression en fonction de la longueur du script?

78
peter

Vous pouvez créer une boucle WHILE en fonction du nombre de fois la longueur de votre script divisée par 8000.

PAR EXEMPLE:

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
14
Kelsey

Je sais que c'est une vieille question, mais ce que j'ai fait n'est pas mentionné ici.

Pour moi, ce qui suit a fonctionné.

DECLARE @info NVARCHAR(MAX)

--SET @info to something big

PRINT CAST(@info AS NTEXT)
163
alfoks

La solution de contournement suivante n'utilise pas l'instruction PRINT. Cela fonctionne bien en combinaison avec SQL Server Management Studio.

SELECT CAST('<root><![CDATA[' + @MyLongString + ']]></root>' AS XML)

Vous pouvez cliquer sur le code XML renvoyé pour le développer dans le visualiseur XML intégré.

Il existe une limite assez généreuse du côté client sur la taille affichée. Allez à Tools/Options/Query Results/SQL Server/Results to Grid/XML data pour l’ajuster si nécessaire.

69
Jirka Hanika

Voici comment cela devrait être fait:

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

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

33
Ben B

Je suis tombé sur cette question et je voulais quelque chose de plus simple ... Essayez ceci:

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

Ce processus imprime correctement le paramètre VARCHAR(MAX) en considérant le 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
9
Andrey Morozov

Je cherchais à utiliser l'instruction print pour déboguer un SQL dynamique, comme je l'imagine, la plupart d'entre vous utilisez print pour des raisons similaires.

J'ai essayé quelques-unes des solutions répertoriées et découvert que la solution de Kelsey fonctionnait avec des modifications mineures (@sql is my @script) n.b. LONGUEUR n'est pas une fonction valide:

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

Comme indiqué, ce code ajoute une nouvelle ligne à la sortie, mais pour le débogage, ce n'est pas un problème pour moi.

La solution de Ben B est parfaite et la plus élégante, bien que pour le débogage il y ait beaucoup de lignes de code, j'ai donc choisi d'utiliser ma légère modification de celle de Kelsey. Cela pourrait valoir la peine de créer un système comme une procédure stockée dans msdb pour le code de Ben B qui pourrait être réutilisé et appelé sur une ligne?

Le code d'Alfoks ne fonctionne malheureusement pas car cela aurait été plus facile.

7
Matthew Radford
 crée la procédure dbo.PrintMax @text nvarchar (max) 
 as 
 begin 
 déclarer @ i int, @newline nchar (2), @print varchar (max); 
 set @newline = nchar (13) + nchar (10); 
 sélectionnez @ i = charindex (@newline, @text); 
 tandis que (@i> 0) 
 commencer
 sélectionnez @print = sous-chaîne (@ text, 0, @ i); 
 tandis que (len (@print)> 8000) 
 commencer
 sous-chaîne d'impression (@ print, 0,8000); 
 sélectionnez @print = sous-chaîne (@ print, 8000, len (@print)); 
 fin
 print @print; 
 sélectionnez @text = sous-chaîne (@ text, @ i + 2, len (@text)); 
 sélectionnez @ i = charindex (@newline, @text); 
 fin
 print @text; 
 end 
3
Adam Gering

Vous pouvez utiliser ceci

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
3
Marwan Almukh

Utilise les sauts de ligne et les espaces comme bon point de rupture:

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,@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 '   '
2
BickiBoy

Si le code source ne pose pas de problème de remplacement de LF par CRLF, aucun débogage n’est requis en suivant les codes simples générés.

--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; 
0
Bill Bai

Ou simplement:

PRINT SUBSTRING(@SQL_InsertQuery, 1, 8000)
PRINT SUBSTRING(@SQL_InsertQuery, 8001, 16000)
0
Yovav

Cela devrait fonctionner correctement, il ne s'agit que d'une amélioration des réponses précédentes.

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
0
vinbhai4u

Voici une autre version. Celui-ci extrait chaque sous-chaîne à imprimer à partir de la chaîne principale au lieu de réduire de 4000 la chaîne principale sur chaque boucle (ce qui pourrait créer beaucoup de très longues chaînes sous le capot - pas certain).

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
0
redcalx