Как печатать 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)
Длина Script составляет около 10 000 символов, и поскольку я использую инструкцию печати, которая может содержать только макс 8000. Поэтому я использую два оператора печати.
Проблема в том, что у меня есть Script, который имеет 18000 символов, тогда я использовал 3 заявления печати.
Итак, есть ли способ установить количество операторов печати в зависимости от длины script?
Ответы
Ответ 1
Вы можете сделать цикл WHILE
, основанный на подсчете длины вашего script, деленной на 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
Ответ 2
Я знаю, что это старый вопрос, но то, что я сделал, здесь не упоминается.
Для меня работали следующие.
DECLARE @info NVARCHAR(MAX)
--SET @info to something big
PRINT CAST(@info AS NTEXT)
Ответ 3
В следующем обходном пути не используется оператор 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
, чтобы при необходимости отрегулировать его.
Ответ 4
Вот как это должно быть сделано:
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*/
Взято из http://ask.sqlservercentral.com/questions/3102/any-way-around-the-print-limit-of-nvarcharmax-in-s.html
Ответ 5
Эта процедура корректно выводит 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
Ответ 6
Перешел через этот вопрос и хотел что-то более простое... Попробуйте следующее:
SELECT [processing-instruction(x)][email protected] FOR XML PATH(''),TYPE
Ответ 7
Я искал использование инструкции 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's. Возможно, стоит создать такую систему, как хранимую процедуру в msdb для кода Ben B, которую можно было бы повторно использовать и вызывать в одной строке?
Код Alfoks не работает, потому что это было бы проще.
Ответ 8
create procedure dbo.PrintMax @text nvarchar(max)
as
begin
declare @i int, @newline nchar(2), @print varchar(max);
set @newline = nchar(13) + nchar(10);
select @i = charindex(@newline, @text);
while (@i > 0)
begin
select @print = substring(@text,0,@i);
while (len(@print) > 8000)
begin
print substring(@print,0,8000);
select @print = substring(@print,8000,len(@print));
end
print @print;
select @text = substring(@text,@i+2,len(@text));
select @i = charindex(@newline, @text);
end
print @text;
end
Ответ 9
Вы можете использовать этот
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
Ответ 10
Использует перевод строки и пробелы в качестве хорошей точки разрыва:
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 ' '
Ответ 11
Или просто:
PRINT SUBSTRING(@SQL_InsertQuery, 1, 8000)
PRINT SUBSTRING(@SQL_InsertQuery, 8001, 16000)
Ответ 12
Существует большая функция PrintMax, написанная Беннеттом Диллом.
Ниже приведена небольшая измененная версия, в которой используется хранимая процедура temp, чтобы избежать "защиты схемы" (идея от 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 <> скрипка Демо
Ответ 13
Здесь другая версия. Этот фрагмент извлекает каждую подстроку для печати из основной строки вместо того, чтобы уменьшать основную строку на 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
Ответ 14
Это должно работать должным образом, это просто улучшение предыдущих ответов.
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
Ответ 15
Если исходный код не будет иметь проблем с заменой 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;
Ответ 16
Я только что создал SP из Бена великолепного ответа:
/*
---------------------------------------------------------------------------------
PURPOSE : Print a string without the limitation of 4000 or 8000 characters.
https://stackoverflow.com/info/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