Print Statement를 사용하여 VARCHAR (MAX)를 인쇄하는 방법은 무엇입니까?


108

다음과 같은 코드가 있습니다.

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)

Script의 길이는 약 10,000 자이고 최대 8000 개까지만 담을 수있는 print Statement를 사용하고 있으므로 두 개의 print 문을 사용하고 있습니다.

문제는 내가 18000 자라고하는 스크립트가있을 때 3 개의 print 문을 사용하는 것입니다.

그렇다면 스크립트의 길이에 따라 인쇄 문 수를 설정할 수있는 방법이 있습니까?


1
PRINT다른 대안 을 사용해야 합니까, 아니면 열려 있습니까?
Martin Smith

내가 만드는 (또는 발견하고 투표)에 대한 문제에 대한 건의 할 것 connect.microsoft.com/SQLServer/Feedback
jmoreno의

답변:


23

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

내 코드를 보면 @Pos 변수를 사용하여 줄 바꿈을 찾고 그에 따라 인쇄합니다. 그래서 어떻게 당신의 코드에서 그것을 사용할 수 있습니까?
peter

@peter 전류를 가져와 그 SUBSTR당시에 다루고있는 부분 만보 고 반복 할 수 있습니다. 또는 매번 8k 제한 이전에 줄 바꿈이있을 것이라는 것을 알고있는 경우 줄 WHILE찾기를 기반으로 수행 할 수 있습니다. 휴식.
Kelsey

@peter 줄 바꿈을 기반으로 반복 할 수 있습니까? 예를 들어 줄 바꿈을 찾으면 줄 바꿈까지 인쇄하고, 줄 바꿈에서 다음 8k 문자까지 substr, 검색, 인쇄, 새 substr 등?
Kelsey

1
함수는 LENGTH ()가 아닌 LEN ()입니다
shiggity

8
나는 print(substring(@script, @Counter * 8000, (@Counter + 1) * 8000))내 대본을 인쇄 하곤 했다.
Lukas Thum

217

나는 그것이 오래된 질문이라는 것을 알고 있지만 내가 한 일은 여기에 언급되지 않았습니다.

나를 위해 다음이 작동했습니다.

DECLARE @info NVARCHAR(MAX)

--SET @info to something big

PRINT CAST(@info AS NTEXT)

4
@gordy-그래서이 방법은 SSMS에서 실제로 작동하지 않는 것 같습니다.
Jirka Hanika

1
이것은 CAST () 또는 CONVERT ()를 사용하는 SQL 2008 R2 SP2 (10.50.1600) 및 SQL 2008 SP2 (10.0.5500)에서 저에게 효과적입니다.

26
16,002 자 이후에 잘림이 표시 max됩니다. DECLARE @info NVARCHAR(MAX) = 'A';SET @info = REPLICATE(@info, 16000) + 'BC This is not printed';PRINT @info;PRINT CAST(@info AS NTEXT);
Martin Smith

6
ntext, text 및 image 데이터 유형 은 향후 버전의 Microsoft SQL Server에서 제거됩니다. 새로운 개발 작업에서 이러한 데이터 유형을 사용하지 말고 현재이를 사용하는 애플리케이션을 수정하도록 계획하십시오.
jumxozizi

5
SQL Server 2014 용 SQL Server Management Studio에서 저에게 적합하지 않았습니다. 16.000 자 이후로 잘립니다. Martin Smith가 작성했습니다.
Jana Weschenfelder

103

다음 해결 방법은 PRINT문을 사용하지 않습니다 . SQL Server Management Studio와 함께 잘 작동합니다.

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

반환 된 XML을 클릭하여 내장 XML 뷰어에서 확장 할 수 있습니다.

표시되는 크기에는 클라이언트 측 제한이 상당히 넉넉합니다. Tools/Options/Query Results/SQL Server/Results to Grid/XML data필요한 경우 조정으로 이동하십시오 .


11
+1. 그러나이 방법은 XML에서 특별한 의미를 가진 문자를 인코딩합니다. 예를 들어 <&lt;.
Iain Samuel McLean Elder

5
당신은하지 않고 스크립트를 작성할 수 있습니다 <root>....와 같은 :SELECT CAST(@MyLongString AS XML)
알리 youhannaei

2
@aliyouhannaei-예, 아니오. 루트 요소가 반드시 필요하지 않다는 것이 맞습니다. 그러나 CDATA 섹션이 없으면 메서드가 일부 문자열에 문제가 발생하기 시작합니다. 특히 <. XML이 아닌 경우 쿼리는 일반적으로 오류가 발생합니다. XML 인 경우 문자열은 다른 "동등한"XML 형식으로 다시 형식화 될 수 있습니다.
Jirka Hanika 2015 년

8
@IainElder-좋은 지적이며 Adam Machanic 의 해결 방법이 있습니다 . 이것은 : SELECT @MyLongString AS [processing-instruction(x)] FOR XML PATH(''). 문자열은 "x"라는 PI에 래핑되지만 PI는 다른 요소에 래핑되지 않습니다 (때문에 PATH('')).
Jirka Hanika 2015 년

무제한으로 설정 - 심지어 "XML 데이터 만회하는 최대 문자"매우 긴 텍스트에 대한이하지 않습니다 작품
마이클 Møldrup

39

이를 수행하는 방법은 다음과 같습니다.

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

http://ask.sqlservercentral.com/questions/3102/any-way-around-the-print-limit-of-nvarcharmax-in-s.html 에서 가져옴


1
훌륭한 기술! BTW,이 기술에 유래 실제 문서 SQLServerCentral.com >>> 출신 sqlservercentral.com/scripts/Print/63240
Rob.Kachmar

2
이것은 나를 위해 일했지만 내 필드 이름 중 하나를 반으로 잘랐습니다. 따라서이 방법을 사용하여 PRINT (@string) 한 다음 EXECUTE (@string)를 실행하면 EXECUTE가 실패합니다.
Johnny Bones

1
PRINT 기능이 나쁜 위치에 줄 바꿈을 추가하고 가치보다 더 많은 정리가 필요하기 때문에 이것은 저에게 효과적이지 않지만 이것이 문제에 가장 가까운 해결책입니다.
Randy Burden

14

이 질문을 발견하고 더 간단한 것을 원했습니다 ... 다음을 시도하십시오.

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

5
더 간단한 것은 SELECT CAST(@STMT AS XML)이미 다른 의견에서 언급 한 바와 같습니다. 정확히 동일한 출력을 생성하며 출력을위한 저장 프로 시저를 만드는 것보다 실제로 덜 복잡합니다.
Felix Bayer

4
@Felix 훨씬 간단하지만 SQL에서는 작동하지 않습니다. XML로 캐스팅하면 SQL 텍스트를 XML로 변환하려고합니다. <,> 및 &를 & lt ;, & gt; 및 & amp; XML에서 허용되지 않는 문자는 처리하지 않습니다. 또한 <와>를 비교하는 상황이있는 경우 해당 요소를 요소라고 생각하고 잘못된 노드 오류를 발생시킵니다.
Edyn

12

이 프로시 저는 VARCHAR(MAX)래핑을 고려 하여 매개 변수를 올바르게 인쇄합니다 .

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

이 절차는 유니 코드 문자와 충돌합니다. 예를 들어 utf8을 처리하는 방법?
mostafa8026

위의 댓글에 대한 답장에서 @script 유형을 nvarchar로 변경하여 수행 할 수 있습니다.
mostafa8026

8

나는 대부분의 사람들이 비슷한 이유로 print를 사용하고 있다고 상상하면서 print 문을 사용하여 동적 SQL을 디버깅하려고했습니다.

나열된 몇 가지 솔루션을 시도한 결과 Kelsey의 솔루션이 사소한 tweeks (@sql은 내 @script 임)에서 작동 함을 발견했습니다. nb LENGTH는 유효한 함수가 아닙니다.

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

이 코드는 주석 처리 된대로 출력에 새 줄을 추가하지만 디버깅을 위해서는 문제가되지 않습니다.

Ben B의 솔루션은 완벽하고 가장 우아하지만 디버깅에는 많은 코드 줄이 필요하므로 Kelsey의 약간 수정을 사용하기로 선택했습니다. 한 줄로 재사용하고 호출 할 수있는 Ben B의 코드에 대해 msdb에 저장 프로 시저와 같은 시스템을 만드는 것이 가치가있을 수 있습니까?

안타깝게도 Alfoks의 코드는 더 쉬웠을 것이기 때문에 작동하지 않습니다.


방금 Ben B의 솔루션을 임시 저장 프로 시저로 추가했습니다. 내 스크립트를 조금 더 깨끗하게 유지하지만 디버깅을위한 많은 줄에 동의합니다.
Zarepheth

4

이것을 사용할 수 있습니다

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

4

Ben의 훌륭한 대답 으로 SP를 만들었습니다 .

/*
---------------------------------------------------------------------------------
PURPOSE   : Print a string without the limitation of 4000 or 8000 characters.
/programming/7850477/how-to-print-varcharmax-using-print-statement
USAGE     : 
DECLARE @Result NVARCHAR(MAX)
SET @Result = 'TEST'
EXEC [dbo].[Print_Unlimited] @Result
---------------------------------------------------------------------------------
*/
ALTER PROCEDURE [dbo].[Print_Unlimited]
    @String NVARCHAR(MAX)
AS

BEGIN

    BEGIN TRY
    ---------------------------------------------------------------------------------

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

    ---------------------------------------------------------------------------------
    END TRY
    BEGIN CATCH
        DECLARE @ErrorMessage VARCHAR(4000)
        SELECT @ErrorMessage = ERROR_MESSAGE()    
        RAISERROR(@ErrorMessage,16,1)
    END CATCH
END

멋지다, 내가 찾던 것!
kooch

3
프로 시저 생성 dbo.PrintMax @text nvarchar (max)
같이
시작하다
    선언 @i int, @newline nchar (2), @print varchar (max); 
    @newline = nchar (13) + nchar (10); 설정
    선택 @i = charindex (@newline, @text);
    동안 (@i> 0)
    시작하다
        select @print = substring (@ text, 0, @ i);
        while (len (@print)> 8000)
        시작하다
            print substring (@ print, 0,8000);
            select @print = substring (@ print, 8000, len (@print));
        종료
        인쇄 @print;
        select @text = substring (@ text, @ i + 2, len (@text));
        선택 @i = charindex (@newline, @text);
    종료
    @text 인쇄;
종료

2

Bennett Dill이 작성한 PrintMax 라는 훌륭한 기능이 있습니다 .

다음은 "스키마 오염"을 피하기 위해 임시 저장 프로 시저를 사용하는 약간 수정 된 버전입니다 ( 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 데모

편집하다:

사용하면 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;');

db <> fiddle 데모


2

줄 바꿈과 공백을 좋은 중단 점으로 사용합니다.

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

완벽하게 작업 함
Jolley71717 2017

2

또는 간단히 :

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

0

다른 버전이 있습니다. 이것은 각 루프에서 메인 문자열을 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

0

이것은 제대로 작동합니다 이것은 이전 답변의 개선 일뿐입니다.

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

소스 코드에 LF가 CRLF로 대체되는 문제가없는 경우 다음 간단한 코드 출력으로 디버깅이 필요하지 않습니다.

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

출력시 잘못된 줄 바꿈 방지를위한 내 PrintMax 버전 :


    CREATE PROCEDURE [dbo].[PrintMax](@iInput NVARCHAR(MAX))
    AS
    BEGIN
      Declare @i int;
      Declare @NEWLINE char(1) = CHAR(13) + CHAR(10);
      While LEN(@iInput)>0 BEGIN
        Set @i = CHARINDEX(@NEWLINE, @iInput)
        if @i>8000 OR @i=0 Set @i=8000
        Print SUBSTRING(@iInput, 0, @i)
        Set @iInput = SUBSTRING(@iInput, @i+1, LEN(@iInput))
      END
    END
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.