I understand that for NVARCHAR(MAX)
there are 4000 maximum values
Your understanding is wrong. NVARCHAR(MAX) can store up to (and beyond sometimes) 2 GB of data (1 billion double-byte characters).
From nchar and nvarchar to online grammar books
nvarchar [ ( n | max ) ]
Symbol | means these are alternatives. that is, you specify either n or the max literal.
If you decide to specify a specific n , then it should be from 1 to 4000, but using max defines it as a large data type of an object ( ntext replacement, which is deprecated).
In fact, in SQL Server 2008 it seems that for a variable, the 2 GB limit can be unlimitedly exceeded by enough space in tempdb ( shown here )
Regarding other parts of your question
Concatenation truncation depends on the data type.
varchar(n) + varchar(n) will be truncated with 8000 characters.nvarchar(n) + nvarchar(n) will be truncated with 4000 characters.varchar(n) + nvarchar(n) will be truncated with 4000 characters. nvarchar has a higher priority, so the result is nvarchar(4,000)[n]varchar(max) + [n]varchar(max) will not truncate (for <2GB).varchar(max) + varchar(n) will not truncate (for <2GB), and the result will be printed as varchar(max) .varchar(max) + nvarchar(n) will not truncate (for <2GB), and the result will be printed as NVARCHAR(MAX) .NVARCHAR(MAX) + varchar(n) first convert the input varchar(n) to nvarchar(n) , and then perform the concatenation. If the varchar(n) string is longer than 4000 characters, then the cast will be nvarchar(4000) and truncation will occur .
String literal data types
If you use the prefix n and the string is <= 4000 characters, it will be typed as nvarchar(n) , where n is the length of the string. Thus, N'Foo' will be considered as nvarchar(3) , for example. If a string is longer than 4000 characters, it will be treated as NVARCHAR(MAX)
If you do not use the prefix n , and the string is <= 8000 characters, it will be typed as varchar(n) , where n is the length of the string. If longer varchar(max)
For both of the above, if the string length is zero, then n set to 1.
New syntax elements.
1. The CONCAT function does not help here
DECLARE @A5000 VARCHAR(5000) = REPLICATE('A',5000); SELECT DATALENGTH(@A5000 + @A5000), DATALENGTH(CONCAT(@A5000,@A5000));
The above returns 8000 for both concatenation methods.
2. Be careful with +=
DECLARE @A VARCHAR(MAX) = ''; SET @A+= REPLICATE('A',5000) + REPLICATE('A',5000) DECLARE @B VARCHAR(MAX) = ''; SET @B = @B + REPLICATE('A',5000) + REPLICATE('A',5000) SELECT DATALENGTH(@A), DATALENGTH(@B);`
Returns
Please note that @A met truncation.
How to solve the problem you are facing.
You get truncated either because you combine the two data types of type max , or because you combine the varchar(4001 - 8000) string varchar(4001 - 8000) with the nvarchar string you entered (even NVARCHAR(MAX) ).
To avoid the second problem, just make sure that all string literals (or at least those that have lengths in the range 4001-8000) are prefixed with n .
To avoid the first problem, change the assignment from
DECLARE @SQL NVARCHAR(MAX); SET @SQL = 'Foo' + 'Bar' + ...;
For
DECLARE @SQL NVARCHAR(MAX) = ''; SET @SQL = @SQL + N'Foo' + N'Bar'
so a NVARCHAR(MAX) participates in the concatenation from the very beginning (since the result of each concatenation will also be NVARCHAR(MAX) , this will spread)
Avoiding truncation when viewing
Make sure the "results to grid" mode is selected, and you can use
select @SQL as [processing-instruction(x)] FOR XML PATH
SSMS parameters allow you to set unlimited length for XML results. The processing-instruction bit avoids problems with characters such as < , displayed as < .