148 votes

Comment imprimer VARCHAR(MAX) à l'aide de l'instruction Print ?

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 et comme j'utilise la déclaration d'impression qui ne peut contenir qu'un maximum de 8 000 caractères. J'utilise donc deux instructions print.

Le problème est que lorsque j'ai un script de 18000 caractères, j'avais l'habitude d'utiliser 3 instructions print.

Existe-t-il un moyen de définir le nombre d'instructions d'impression en fonction de la longueur du script ?

1 votes

Devez-vous utiliser PRINT ou êtes-vous ouvert à d'autres alternatives ?

0 votes

Je suggère de créer (ou de trouver et de voter) pour un problème sur connect.microsoft.com/SQLServer/Feedback

7 votes

10 ans plus tard, ce genre d'astuces est toujours nécessaire. C'est triste, vraiment

286voto

alfoks Points 643

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

Pour moi, la procédure suivante a fonctionné (jusqu'à 16 000 caractères)

DECLARE @info NVARCHAR(MAX)

--SET @info to something big

PRINT CAST(@info AS NTEXT)

Si vous avez plus de 16k chars, vous pouvez combiner avec la réponse de @Yovav comme ceci (64k devrait être suffisant pour tout le monde ;)

    print cast( substring(@info, 1, 16000) as ntext )
    print cast( substring(@info, 16001, 32000) as ntext )
    print cast( substring(@info, 32001, 48000) as ntext )
    print cast( substring(@info, 48001, 64000) as ntext )

0 votes

Quelqu'un a-t-il appliqué avec succès cette méthode à des données réelles ? J'utilise SQL Server 2008 R2 SP2. SQL Server Management Studio comme client. PRINT La documentation semble promettre une troncature à 4K/8K caractères (ntext/text), mais étrangement, je ne vois qu'une troncature à 16K caractères, ce qui me laisse perplexe quant à son origine et à la manière de la désactiver.

0 votes

@JirkaHanika Je vois la même troncature à 16k en utilisant convert(text, @vmax)

6 votes

@gordy - Il me semble donc que cette méthode ne fonctionne pas vraiment dans SSMS.

133voto

Jirka Hanika Points 8266

La solution suivante n'utilise pas l'option PRINT déclaration. Il fonctionne bien en combinaison avec le SQL Server Management Studio.

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

Vous pouvez cliquer sur le fichier XML retourné pour le développer dans la visionneuse XML intégrée.

La taille affichée est assez généreusement limitée côté client. Pour cela, il faut se rendre sur le site Tools/Options/Query Results/SQL Server/Results to Grid/XML data pour l'ajuster si nécessaire.

12 votes

+1. Mais cette méthode permet d'encoder des caractères qui ont une signification particulière dans XML. Par exemple, < est remplacé par &lt; .

7 votes

Vous pouvez écrire script sans <root>.... comme : SELECT CAST(@MyLongString AS XML)

2 votes

@aliyouhannaei - Oui et non. Vous avez raison de dire que l'élément Root n'est pas strictement nécessaire. Mais, sans la section CDATA, votre méthode commence à avoir des problèmes avec certaines chaînes. En particulier celles qui contiennent <. S'il ne s'agit pas de XML, la requête est généralement rejetée. S'il s'agit de XML, la chaîne peut être reformatée dans une autre forme XML "équivalente".

46voto

Ben B Points 331

Voici comment procéder :

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

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

1 votes

Excellente technique ! BTW, l'article à l'origine de cette technique provient de SQLServerCentral.com >>> sqlservercentral.com/scripts/Print/63240

2 votes

Cela a fonctionné pour moi, mais l'un de mes noms de champ a été divisé par deux. Donc, si j'utilise cette méthode pour PRINT (@string) et ensuite EXECUTE (@string), l'EXECUTE échoue.

1 votes

Cela ne fonctionne pas pour moi car la fonction PRINT ajoute des sauts de ligne aux mauvais endroits et nécessiterait plus de nettoyage qu'il n'en vaut la peine, mais c'est la solution la plus proche du problème.

30voto

Kelsey Points 26456

Vous pourriez faire une WHILE en se basant sur le décompte de votre script divisé par 8000.

EG :

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

0 votes

Si vous regardez mon code, j'utilise également la variable @Pos pour trouver le saut de ligne et l'imprimer en conséquence. Comment puis-je utiliser cela dans votre code ?

0 votes

@peter Vous pouvez simplement prendre la SUBSTR et ne regarder que la partie que vous traitez à ce moment-là et itérer sur elle ou si vous savez qu'il y aura un saut de ligne avant la limite de 8k à chaque fois, alors faites simplement la commande WHILE basé sur la recherche de sauts de ligne.

0 votes

@peter pouvez-vous faire des boucles basées sur les sauts de ligne ? Par exemple, rechercher un saut de ligne, s'il est trouvé, imprimer jusqu'au saut de ligne, substr à partir du saut de ligne jusqu'aux 8k caractères suivants, rechercher, imprimer, nouveau substr, etc ?

16voto

Edyn Points 448

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

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

6 votes

Plus simple serait SELECT CAST(@STMT AS XML) comme indiqué dans un autre commentaire. Le résultat est exactement le même et il est effectivement moins compliqué que de créer une procédure stockée pour le résultat.

5 votes

@Felix Bien que cela soit beaucoup plus simple, cela ne fonctionne pas tout à fait pour SQL. Casting to XML tente de convertir le texte SQL en XML. Il remplacera <, > et & par <, > et & et ne gérera pas les caractères non autorisés en XML. En outre, si vous effectuez une comparaison entre < et >, il pense qu'il s'agit d'un élément et génère une erreur de nœud non valide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X