문 인쇄를 사용하여 VARCHAR(MAX)를 인쇄하는 방법은 무엇입니까?
코드는 다음과 같습니다.
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)
스크립트의 길이는 약 10,000자이며 최대 8000자까지만 저장할 수 있는 print 문을 사용하고 있기 때문입니다.그래서 저는 두 개의 인쇄문을 사용하고 있습니다.
문제는 제가 18000자 정도의 스크립트를 가지고 있을 때, 저는 3개의 인쇄문을 사용했습니다.
그럼 스크립트 길이에 따라 인쇄문 수를 설정할 수 있는 방법이 있나요?
오래된 질문인 건 알지만, 제가 한 일은 여기에 언급되지 않았습니다.
저의 경우 다음 작업이 가능합니다(최대 16,000자).
DECLARE @info NVARCHAR(MAX)
--SET @info to something big
PRINT CAST(@info AS NTEXT)
만약 당신이 16,000개 이상의 문자를 가지고 있다면, 당신은 이렇게 @Yovav의 대답과 결합할 수 있습니다 (64,000이면 누구에게나 충분할 것입니다 ;)
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 )
다음 해결 방법은 다음을 사용하지 않습니다.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필요한 경우 조정할 수 있습니다.
이 작업을 수행하는 방법은 다음과 같습니다.
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 에서 발췌
당신은 할 수 있습니다.WHILE스크립트 길이를 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
이 질문을 접하게 되었고 좀 더 간단한 것을 원하게 되었습니다.다음을 시도합니다.
SELECT [processing-instruction(x)]=@Script FOR XML PATH(''),TYPE
/*
---------------------------------------------------------------------------------
PURPOSE : Print a string without the limitation of 4000 or 8000 characters.
https://stackoverflow.com/questions/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
이 프로세스는 올바르게 인쇄됩니다.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
저는 여러분 대부분이 비슷한 이유로 인쇄를 사용하고 있다고 생각하기 때문에 print 문을 사용하여 동적 SQL을 디버깅하려고 합니다.
나열된 솔루션 중 몇 가지를 시도해 본 결과 Kelsey의 솔루션은 마이너 위크(@sql은 나의 @script) n.b. 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에 저장 프로시저와 같은 시스템을 만드는 것이 가치가 있을 수도 있습니다.
불행하게도 알폭스의 코드는 작동하지 않습니다. 왜냐하면 그것은 더 쉬웠을 것이기 때문입니다.
이것을 사용할 수 있습니다.
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
간단히 말하면:
PRINT SUBSTRING(@SQL_InsertQuery, 1, 8000)
PRINT SUBSTRING(@SQL_InsertQuery, 8001, 16000)
베넷 딜이 쓴 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;');
편집:
용사를 합니다.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;');
생성 절차 dbo.PrintMax @text nvarchar(최대)~하듯이시작한다.@iint, @newline nchar(2), @print varchar(max)를 선언합니다.set @newline = nchar(13) + nchar(10);@i = charindex(@newline, @text)를 선택합니다. while (@i > 0)시작한다.@print = 하위 문자열(@text,0,@i)을 선택합니다. while (len(@print) > 8000)시작한다.인쇄 하위 문자열(@print,0,8000); @print = 하위 문자열(@print,8000,len(@print))을 선택합니다.;끝.print@print;@text = 하위 문자열(@text,@i+2,len(@text))을 선택합니다.;@i = charindex(@newline, @text)를 선택합니다. 끝.print@text;끝.
선 피드 및 공백을 좋은 중단점으로 사용:
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 ' '
출력 시 잘못된 줄 바꿈을 방지하기 위한 내 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
여기 다른 버전이 있습니다.이것은 각 루프에서 주 문자열을 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
이것은 제대로 작동해야 합니다. 이것은 단지 이전 답변의 개선일 뿐입니다.
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
소스 코드가 CRLF로 대체되는 LF에 문제가 없을 경우 간단한 코드 출력을 따라 디버깅할 필요가 없습니다.
--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;
관심 있는 사용자가 powershell로 텍스트 파일을 생성하고 스칼라 코드를 실행한 경우:
$dbconn = "Data Source=sqlserver;" + "Initial Catalog=DatabaseName;" + "User Id=sa;Password=pass;"
$conn = New-Object System.Data.SqlClient.SqlConnection($dbconn)
$conn.Open()
$cmd = New-Object System.Data.SqlClient.SqlCommand("
set nocount on
DECLARE @sql nvarchar(max) = ''
SELECT
@sql += CHAR(13) + CHAR(10) + md.definition + CHAR(13) + CHAR(10) + 'GO'
FROM sys.objects AS obj
join sys.sql_modules AS md on md.object_id = obj.object_id
join sys.schemas AS sch on sch.schema_id = obj.schema_id
where obj.type = 'TR'
select @sql
", $conn)
$data = [string]$cmd.ExecuteScalar()
$conn.Close()
$data | Out-File -FilePath "C:\Users\Alexandru\Desktop\bigstring.txt"
이 스크립트는 DB에서 모든 트리거가 포함된 큰 문자열을 가져오기 위한 것입니다.
언급URL : https://stackoverflow.com/questions/7850477/how-to-print-varcharmax-using-print-statement
'programing' 카테고리의 다른 글
| MDF 파일이란? (0) | 2023.05.07 |
|---|---|
| Python3에서 인덱스별로 dict_keys 요소 액세스 (0) | 2023.05.07 |
| WPF에서 메서드에 바인딩하시겠습니까? (0) | 2023.05.07 |
| 프로세스가 끝날 때까지 대기 (0) | 2023.05.07 |
| c# Excel interop 학습 리소스 (0) | 2023.05.07 |