如何使用Print Statement打印VARCHAR(MAX)?

pet*_*ter 94 sql t-sql sql-server sql-server-2005 sql-server-2008

我有一个代码是:

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)
Run Code Online (Sandbox Code Playgroud)

脚本的长度大约是10,000个字符,因为我使用的print语句最多只能容纳8000个.所以我使用了两个打印语句.

问题是,当我有一个脚本,比如18000个字符,然后我习惯使用3个打印语句.

那么有没有办法可以根据脚本的长度设置打印语句的数量?

alf*_*oks 188

我知道这是一个老问题,但我所做的并没有在这里提到.

对我来说,以下工作.

DECLARE @info NVARCHAR(MAX)

--SET @info to something big

PRINT CAST(@info AS NTEXT)
Run Code Online (Sandbox Code Playgroud)

  • 我看到在16,002个字符后截断,但仍然比`max`更长.`DECLARE @info NVARCHAR(MAX)='A'; SET @info = REPLICATE(@info,16000)+'BC这不打印'; PRINT @info; PRINT CAST(@info AS NTEXT);` (22认同)
  • [ntext,text和image数据类型](https://msdn.microsoft.com/en-us/library/ms187993(v = sql.110).aspx)将在未来版本的Microsoft SQL Server中删除.避免在新的开发工作中使用这些数据类型,并计划修改当前使用它们的应用程序. (6认同)
  • 在SQL Server Management Studio for SQL Server 2014中没有为我工作.它在16.000个字符后削减.由马丁史密斯写的. (5认同)
  • @gordy - 所以在我看来,这种方法在SSMS中并不真正起作用. (3认同)

Jir*_*ika 93

以下解决方法不使用该PRINT语句.它与SQL Server Management Studio结合使用效果很好.

SELECT CAST('<root><![CDATA[' + @MyLongString + ']]></root>' AS XML)
Run Code Online (Sandbox Code Playgroud)

您可以单击返回的XML以在内置XML查看器中展开它.

显示的大小对客户端有一个非常慷慨的限制.Tools/Options/Query Results/SQL Server/Results to Grid/XML data如果需要,转到调整它.

  • +1.但是这种方法对XML中具有特殊含义的字符进行编码.例如,`<`替换为`&lt;`. (11认同)
  • @IainElder - 这是一个很好的观点,有一个解决方法[来自Adam Machanic](http://stackoverflow.com/a/2760023/1235565).就是这样:`SELECT @MyLongString AS [processing-instruction(x)] FOR XML PATH('')`.该字符串将包含在名为"x"的PI中,但PI不会包含在另一个元素中(因为`PATH('')`). (8认同)
  • 你可以在没有`<root> ....的情况下编写脚本,如:`SELECT CAST(@MyLongString AS XML)` (5认同)
  • @aliyouhannaei-是和否。您认为根元素不是严格必需的。但是,如果没有CDATA部分,您的方法就会遇到一些字符串问题。特别是那些包含&lt;。如果它们不是XML,则查询通常会出错。如果它们是XML,则字符串最终可能会重新格式化为另一种“等效” XML形式。 (2认同)

小智 38

这是应该如何做到的:

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*/
Run Code Online (Sandbox Code Playgroud)

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

  • 这对我有用,但它也将我的一个字段名称切成两半.因此,如果我将此方法用于PRINT(@string)然后执行EXECUTE(@string),则EXECUTE将失败. (2认同)

Kel*_*sey 17

您可以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
Run Code Online (Sandbox Code Playgroud)

  • 我使用`print(substring(@ script,@ Counter*8000,(@ Counter + 1)*8000))`来打印我的脚本. (4认同)

Edy*_*dyn 13

遇到这个问题,想要更简单的东西...尝试以下方法:

SELECT [processing-instruction(x)]=@Script FOR XML PATH(''),TYPE
Run Code Online (Sandbox Code Playgroud)

  • @Felix虽然这会简单得多,但对SQL来说却不太适用.转换为XML会尝试将SQL文本转换为XML.它会将<,>和&替换为&lt;,&gt; 和&amp; 它不会处理XML中不允许的字符.此外,如果你有一个比较<和then>的情况,它认为这是一个元素并抛出一个无效的节点错误. (4认同)
  • 更简单的是`SELECT CAST(@STMT AS XML)`,如另一条评论中所述.产生完全相同的输出,并且确实比为输出创建存储过程简单. (3认同)

And*_*zov 11

这个proc正确地打印出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
Run Code Online (Sandbox Code Playgroud)


Mat*_*ord 7

我正在寻找使用print语句来调试一些动态的sql,因为我想大多数人都是因为simliar原因而使用print.

我尝试了一些列出的解决方案,发现Kelsey的解决方案适用于小问题(@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)
Run Code Online (Sandbox Code Playgroud)

这段代码注释会在输出中添加一个新行,但是对于调试来说,这对我来说不是问题.

Ben B的解决方案是完美的,并且是最优雅的,虽然调试是很多代码行,所以我选择使用我对Kelsey的轻微修改.可能值得在msdb中为Ben B的代码创建一个类似存储过程的系统,可以在一行中重用和调用它?

不幸的是,Alfoks的代码不起作用,因为这样会更容易.


Yov*_*vav 7

或者简单地:

PRINT SUBSTRING(@SQL_InsertQuery, 1, 8000)
PRINT SUBSTRING(@SQL_InsertQuery, 8001, 16000)
Run Code Online (Sandbox Code Playgroud)


Yov*_*vav 7

我刚刚根据Ben 的精彩回答创建了一个 SP :

/*
---------------------------------------------------------------------------------
PURPOSE   : Print a string without the limitation of 4000 or 8000 characters.
/sf/ask/549533421/
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
Run Code Online (Sandbox Code Playgroud)


Mar*_*ukh 5

你可以用这个

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
Run Code Online (Sandbox Code Playgroud)