[n]varchar truncation

I was very happy with the response to my SQL Saturday session in Albuquerque. To those who attended and provided me with feedback, thank you.

One of the items I covered led to this tweet from @coffegrl:

thrilled! I was just able to use something i learned at #sqlsatabq. that's ROI for you :)

Which just made my day yesterday. Anyway, here’s what she was talking about. Have a look at this script:


DECLARE @stmt NVARCHAR(MAX);
SELECT @stmt = N'foo' + REPLICATE(N'A', 4000) + N'bar';
SELECT LEN(@stmt), LEFT(@stmt, 5), RIGHT(@stmt, 5);

What happens when you run it? Ideally, the results should be 4006, ‘fooAA’ and ‘AAbar’. But that’s not the case. Even though @stmt is NVARCHAR(MAX), the four components of the string concatenation (‘foo’, ‘A’, the results of REPLICATE, and ‘bar’) are not. As a result, the value that is constructed is, in this case, an NVARCHAR(4000), which is then written to @stmt.

Here’s one way to fix it:


DECLARE @stmt NVARCHAR(MAX);
SELECT @stmt = N'foo' + REPLICATE(CAST(N'A' AS NVARCHAR(MAX)), 4000) + N'bar';
SELECT LEN(@stmt), LEFT(@stmt, 5), RIGHT(@stmt, 5);

And another:


DECLARE @stmt NVARCHAR(MAX);
SELECT @stmt = N'foo' + CAST(REPLICATE(N'A', 4000) AS NVARCHAR(MAX)) + N'bar';
SELECT LEN(@stmt), LEFT(@stmt, 5), RIGHT(@stmt, 5);

And another:


DECLARE @stmt NVARCHAR(MAX);
SELECT @stmt = CAST(N'foo' AS NVARCHAR(MAX)) + REPLICATE(N'A', 4000) + N'bar';
SELECT LEN(@stmt), LEFT(@stmt, 5), RIGHT(@stmt, 5);

And the same is true for VARCHAR (assuming you replace the 4000’s with 8000’s). So, the lesson is, when concatenating large strings in SQL be careful that it doesn’t trunca