T-SQL VARCHAR(MAX) Truncated

2019-01-26 09:38发布

问题:

DECLARE @str VARCHAR (MAX);

SELECT @str = COALESCE(@str + CHAR(10), '') +
       'EXECUTE CreateDeno ' + CAST(ID AS VARCHAR) 
FROM   GL_To_Batch_Details
WHERE  TYPE = 'C' AND
       Deno_ID IS NULL;

--PRINT @str;--SELECT @str;
**EXEC(@str);**

EDITED

Does EXECUTE statement truncate strings to 8,000 chars like PRINT? How can I execute a dynamic SQL statement having more than 8,000 chars?

Any suggestion would be warmly appreciated.

回答1:

PRINT is limited to 8k in output.

There is also an 8k limit in SSMS results pane.

Go to

tools -> options -> query results

to see the options.

To verify the length of the actual data, check:

SELECT LEN(@str)



回答2:

When concatenating strings and the result is of type VARCHAR(MAX) and is over 8000 characters, at least one parameter and/or element being used in the concatenation need to be of the VARCHAR(MAX) type otherwise truncation will occur in the resultant string and will not be executable in an EXEC statement.

Example:

DECLARE @sql AS VARCHAR(MAX);
/* DECLARE @someItem AS VARCHAR(100); -- WILL CAUSE TRUNCATION WHEN @sql HAS LEN > 8000 */
DECLARE @someItem AS VARCHAR(MAX); -- All string variables need to be VARCHAR(MAX) when concatenating to another VARCHAR(MAX)

SET @someItem = 'Just assume the resulting @sql variable goes over 8000 characters...';
SET @sql = 'SELECT Something FROM Somewhere WHERE SomeField = ''' + @someItem + '''';

EXEC (@sql);
--PRINT @sql;

More information on MSDN.

"If the result of the concatenation of strings exceeds the limit of 8,000 bytes, the result is truncated. However, if at least one of the strings concatenated is a large value type, truncation does not occur."



回答3:

The default length of a varchar is 30 characters:

CAST (ID AS VARCHAR) 

Is it possible that id is longer than 30 characters?



回答4:

The PRINT command is certainly limited to 8000 chars, irrespective of the length of the output (or whether it is varchar(max)). To work around this you need to output the string in chunks of <8000 chars


Update: In answer to your edit, exec doesn't limit the string length. I've put together the following example to show this:

DECLARE @str VARCHAR (MAX);


;WITH CTE_Count AS
(
    select counter = 1
    union all
    select counter = counter+1
    from CTE_Count
    Where counter < 2000

)
SELECT             
    @str=COALESCE(@str + CHAR (10) ,
        '' ) + 'select value=' + CAST (counter AS VARCHAR) 
from
    CTE_Count

Option (MAXRECURSION 0)

PRINT len(@str);--SELECT @str;

exec (@str)

Running this prints the length as 34892 chars, and all 2000 execute statements do run (be warned, it may take a few mins!)



回答5:

It happens when you concatenate literals if one is not a varchar(max) the result ill be "implicit casted" to varchar(8000).

To generate a literal varchar(max) all parts must be varchar(max). Note: It happened to me doing updates on varchar(max) columns, never tested with the EXEC command.

Also as noted in previous answers the print command holds a limit but you can try selecting that variable instead of printing it. (also ther's a limit on that select length you can configure on MS-SMS)



回答6:

I also wanted to see what I was sending to Exec, and was confused by the PRINT limit. Had to write a proc to print in chunks.

CREATE PROCEDURE [dbo].[KFX_PrintVarcharMax] 
    @strMax varchar(max)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE 
        @index int = 0,
        @start int = 1,
        @blkSize int = 2000;


    WHILE @Start < LEN(@strMax)
    BEGIN
        IF @start + @blkSize >= LEN(@strMax)
        BEGIN
            -- If remainder is less than blocksize print the remainder, and exit.
            PRINT SUBSTRING(@strMax, @start, @blkSize)
            BREAK;
        END
        -- Else find the next terminator (beyond the blksize)
        SET @index = CHARINDEX(CHAR(10), @strMax, @start + @blkSize);
        if @index >= @start
        BEGIN
            PRINT SubString(@strMax, @start, @index - @start + 1)
            SET @start = @index + 1;
            SET @blkSize  = CASE WHEN @start + 2000 < LEN(@strMax) THEN 2000 
                            ELSE LEN(@strMax) - @start + 1 END
        END
        ELSE
        BEGIN
            -- No char(10) found.  Just print the rest.
            PRINT SUBSTRING(@strMax, @start, LEN(@strMax))
            BREAK;
        END 
    END

END


标签: tsql