varchar(max) is truncating the string when set in a variable - sql

I'm trying to print a dynamic query but what's happening is while printing the query the characters are getting truncated.
declare #sql varchar(max)
set #sql = cast('select*from.................length is huge' as varchar(max))
print #sql
Any idea how to solve it?

The SQL function PRINT will only show a maximum of 8000 char, the variable still has the full content. Try running this:
PRINT LEN(#sql)
You should see a much larger number.

Related

EXEC sp_executesql #sql limitation

I am having problem with executing dynamic SQL Server code.
I have an insert into temp table and the number of chars is more than 4000.
I tried to split into two variables and then concatenated them but problem is
EXEC sp_executesql #sql,
N'#DimStartDate int, #DimEndDate bigint',
#DimStartDate, #DimEndDate;
I found on net that EXEC(#sql1+#sql2) is solution but I really need input parameters. How can I solve this?
I have dealt with a similar issue before, like below. Basically you need to separate your main query into pieces, then combine them in the end and use sp_EXECUTESQL to run your dynamic query.
DECLARE #SQL_Part1 varchar(4000);
DECLARE #SQL_Part2 varchar(4000);
DECLARE #SQL_Part3 varchar(4000);
DECLARE #SQL_Part4 varchar(4000);
DECLARE #SQL_Part5 varchar(4000);
DECLARE #SQL_FullQuery nvarchar(MAX);
.. set your queries...
SET #SQL_FullQuery = CAST(#SQL_Part1 + #SQL_Part2 + #SQL_Part3 + #SQL_Part4 + #SQL_Part5 as nvarchar(MAX));
EXEC sp_EXECUTESQL #SQL_FullQuery;
I have had no problem with sp_executesql on strings very long strings. You simply need to declare the query to be long enough:
declare #sql nvarchar(max);
You can have an error inserting into a table if the row length is too long for the table. That would have nothing to do with the dynamic statement. The maximum length of a row is limited in SQL Server -- although you can use long strings and blobs to work around that.
Not sure exactly where the problem is. SQL Server will happily execute more than 4,000 characters, so your SQL must be getting truncated somewhere else. Here is an example where I've manually built up a batch that is more than 4,000 characters total so you can see that all three SELECT statements run and if you copy and paste the middle result you'll see it has the y at the end:
DECLARE #sql nvarchar(max) = N'SELECT 1;'
+ N'SELECT ''' + CONVERT(nvarchar(max), REPLICATE('x', 4096)) + N'y'';';
+ N'SELECT 2;';
EXEC sys.sp_executesql #sql;
Results:

Varchar(Max) is not working in Exec

I have a variable which has SQL string stored in it and am executing it through exec()
Declare #sql varchar(max)
set #sql = Concat('select...',#var,'..') -- large string
exec (#sql)
but am getting error saying
Incorrect syntax near sometext
It is because the variable #sql cannot hold the entire string. So I fixed by splitting the string into two different variables and executed it
Declare #sql1 varchar(max),#sql2 varchar(max)
set #sql1 = 'select...'
set #sql2 = ' from sometable join....'
exec (#sql1+#sql2)
I checked the data length of #sql1+ #sql2
Select Datalength(#sql1+ #sql2)
It returned 14677
Now question is why varchar(max) cannot store 14677 bytes of information? When the documents says it can store upto 2GB of data
It is probably this you are running against:
DECLARE #part1 VARCHAR(5000)=REPLICATE('a',5000);
DECLARE #part2 VARCHAR(5000)=REPLICATE('a',5000);
SELECT DATALENGTH(#part1),DATALENGTH(#part2),DATALENGTH(#part1+#part2);
The result is 5000,5000,8000
If one of the summands is a MAX type, you'll get the expected result
SELECT DATALENGTH(#part1),DATALENGTH(#part2),DATALENGTH(CAST(#part1 AS VARCHAR(MAX))+#part2);
The result is 5000,5000,10000
This is often seen in connection with
string concatenation
usage of (older) functions returning VARCHAR(8000) as former max length
column definitions
UPDATE Same with CONCAT
SELECT DATALENGTH(#part1),DATALENGTH(#part2),DATALENGTH(CONCAT(#part1,#part2));
SELECT DATALENGTH(#part1),DATALENGTH(#part2),DATALENGTH(CONCAT(CAST(#part1 AS VARCHAR(MAX)),#part2));
The approach of creating two varchar(max) data elements and combining them via "exec (#sql1+#sql2)" works and I appreciate the suggestion. I ran into the same issue and will be using this trick in the future.
For me, one varchar(max) data element got truncated when attempted to be executed. Split it into two varchar(max) data elements (no syntax change) and executed without issue.

How to run a more than 8000 characters SQL statement from a variable?

I can use the following code for tiny little queries:
DECLARE #sql VARCHAR(8000)
SET #sql = 'SELECT * FROM myTable'
Exec #sql
The above method is very useful in order to maintain large amounts of code, especially when we need to make changes once and have them reflected everywhere.
My problem is my query (it's only one single query) that I want to feed into the #sql variable uses more than 25 table joins, some of them on temporary table variables, incorporates complex operations and it is hence much more than 8000 characters long.
I wished to use TEXT data type to store this query, but MSDN shows a warning message that Microsoft is planning to remove Text, NText and Image data types from their next versions. I wish my code to run in future too.
I thought of storing this query in a separate file, but as it uses joins on table variables and other procedure-specific parameters, I doubt if this is possible.
Kindly tell me a method to store a large query into a variable and execute it multiple times in a procedure.
The problem is with implicit conversion.
If you have Unicode/nChar/nVarChar values you are concatenating, then SQL Server will implicitly convert your string to VarChar(8000), and it is unfortunately too dumb to realize it will truncate your string or even give you a Warning that data has been truncated for that matter!
When concatenating long strings (or strings that you feel could be long) always pre-concatenate your string building with CAST('' as nVarChar(MAX)) like so:
SET #Query = CAST('' as nVarChar(MAX))--Force implicit conversion to nVarChar(MAX)
+ 'SELECT...'-- some of the query gets set here
+ '...'-- more query gets added on, etc.
What a pain and scary to think this is just how SQL Server works. :(
I know other workarounds on the web say to break up your code into multiple SET/SELECT assignments using multiple variables, but this is unnecessary given the solution above.
For those who hit a 4000 character max, it was probably because you had Unicode so it was implicitly converted to nVarChar(4000).
Warning:
You still Cannot have a Single Unbroken Literal String Larger than 8000 (or 4000 for nVarChar).
Literal Strings are those you hard-code and wrap in apostrophe's.
You must Break those Strings up or SQL Server will Truncate each one BEFORE concatenating.
I add ' + ' every 20 lines (or so) to make sure I do not go over.
That's an average of at most 200 characters per line - but remember, spaces still count!
Explanation:
What's happening behind the scenes is that even though the variable you are assigning to uses (MAX), SQL Server will evaluate the right-hand side of the value you are assigning first and default to nVarChar(4000) or VarChar(8000) (depending on what you're concatenating). After it is done figuring out the value (and after truncating it for you) it then converts it to (MAX) when assigning it to your variable, but by then it is too late.
If you are on SQL Server 2008 or newer you can use VARCHAR(MAX)
DECLARE #sql VARCHAR(MAX)
DECLARE #sql VARCHAR(max)
SET #sql = 'SELECT * FROM myTable'
Exec #sql
Note:
Print(#sql)
only show the first 8000 characters!
use
EXEC
(
'
--your sql script here
'
)
Problem is because your string has limit 8000 symbols by default. To prevent this you should convert it to (N)VARCHAR(MAX)
DECLARE #sql VARCHAR(8000)
SET #sql = CAST('SELECT * FROM myTable' AS VARCHAR(MAX))
--Check length of variable
PRINT 'Length is: '+CAST(LEN(#sql) AS VARCHAR)+ 'symbols'
Exec #sql
You should read the answer of this post which explains extremely well the situation :
SQL NVARCHAR and VARCHAR Limits
If the length x of your string is below 4000 characters, a string will be transformed into nvarchar(x)
If the length y is between 4000 and 8000, varchar(y)
If the length is more than 8000 characters, nvarchar(max) which can store up to 2GB.
Problem is that nvarchar(max) + varchar(y) = nvarchar(max) + nvarchar(4000) ; SQL will convert your varchar(y) into nvarchar(y) or nvarchar(4000) if y is greater than 4000 and lesser than 8000, truncating your string !
Well I ran to this before (in SQL 2005) and I can tell you that you have two options:
1 - Use the sys.sp_sqlexec stored procedure that can take a param of type text (IMO this is the way to go). Don't mind the warning. In SQL 2008 ntext is still supported, and if you do the varchar(max) thingy there, it will work. So basically, if you have 2008, both the text solution and the varchar(max) will work, so you will have time to change it =-). In 2012 though, only the varchar(max) will work, therefore you'll have to change it before upgrading.
2- (This is what I did at first) Check THIS post: http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=52274 and do what user "Kristen" says. Worked like a charm for me. Don't forget to pre-set them to an empty string. If you understood my post you know by now that in SQL 2008 or newer is silly to do this.
I had the same issue. I have a SQL which was more than 21,000 characters. For some reason,
Declare #SQL VARCHAR(MAX)
EXEC(#SQL)
would come up with several issues
I had to finally split it up in multiple variables equally and then it worked.
Declare #SQL1 VARCHAR(MAX) = 'First Part'
Declare #SQL2 VARCHAR(MAX) = 'Second Part'
Declare #SQL3 VARCHAR(MAX) = 'Third Part'
Declare #SQL4 VARCHAR(MAX) = 'Fourth Part'
Set #SQL= #SQL1 + #SQL2 + #SQL3 + #SQL4
EXEC(#SQL)
There is no solution for this along the way that you are doing it. MsSql as of 2012 supports Ntext for example that allows you to go beyond 8000 characters in a variable. The way to solve this is to make multiple variables or multiple rows in a table that you can iterate through.
At best with a MsSql version the max size of a variable is 8000 characters on the latest version as of when this was typed. So if you are dealing with a string of say 80,000 characters. You can parse the data into ten variables of 8000 characters each (8000 x 10 = 80,000) or you can chop the variable into pieces and put it into a table say LongTable (Bigstring Varchar(8000)) insert 10 rows into this and use an Identity value so you can retrieve the data in the same order.
The method you are trying will not work with MsSql currently.
Another obscure option that will work but is not advisable is to store the variable in a text file by using command shell commands to read/write the file. Then you have space available to you beyond 8000 characters. This is slow and less secure than the other methods described above.
ALTER PROCEDURE [dbo].[spGetEmails]
AS
BEGIN
SET NOCOUNT ON;
-- Insert statements for procedure here
declare #p varbinary(max)
set #p = 0x
declare #local table (col text)
SELECT #p = #p + 0x3B + CONVERT(varbinary(100), Email)
FROM tbCarsList
where email <> ''
group by email
order by email
set #p = substring(#p, 2, 10000000)
insert #local values(cast(#p as varchar(max)))
select col from #local
END
I have been having the same problem, with the strings being truncated. I learned that you can execute the sp_executesql statement multiple times.
Since my block of code was well over the 4k/Max limit, I break it out into little chunks like this:
set #statement = '
update pd
set pd.mismatchtype = 4
FROM [E].[dbo].[' + #monthName + '_P_Data] pd
WHERE pd.mismatchtype is null '
exec sp_executesql #statement
set #statement = 'Select * from xxxxxxx'
exec sp_executesql #statement
set #statement = 'Select * from yyyyyyy '
exec sp_executesql #statement
end
So each set #Statement can have the varchar(max) as long as each chunk itself is within the size limit (i cut out the actual code in my example, for space saving reasons)
Before print convert into cast and change datatype.
PRINT CAST(#sql AS NTEXT)
Now, try it.
If what you are trying to accomplish is to do this in Management Studio, the script below might help.
DECLARE #Len INT = 5
DECLARE #Str VARCHAR(MAX) = '1111122222333334444455555'
DECLARE #TmpStr VARCHAR(MAX)
DECLARE #Return TABLE (RetStr VARCHAR(MAX))
WHILE(LEN(#Str) > 0)
BEGIN
SET #TmpStr = LEFT(#Str, #Len)
IF(LEN(#Str) > #Len)
SET #Str = RIGHT(#Str, LEN(#Str) - #Len)
ELSE
SET #Str = ''
INSERT INTO #Return SELECT #Str
END
SELECT * FROM #Return
There #Len should be 8000, as this is the maximum length Management Studio shows. #Str is the text that is longer than 8000 characters.

nvarchar(max) still being truncated

So I'm writing a stored procedure in MS SQL Server 2008. It's a really long query and I have to write it dynamically, so I create a variable called #Query and make it of type NVARCHAR(MAX). Now, I have been told that in modern versions of SQL Server, NVARCHAR(MAX) can hold a ridiculous amount of data, way more than the original 4000 character maximum. However, #Query is still getting truncated to 4000 characters when I try to print it out.
DECLARE #Query NVARCHAR(max);
SET #Query = 'SELECT...' -- some of the query gets set here
SET #Query = #Query + '...' -- more query gets added on, etc.
-- later on...
PRINT LEN(#Query) -- Prints out 4273, which is correct as far as I can tell
PRINT #Query -- Truncates value to 4000 characters
EXEC sp_executesql #Query -- totally crashes due to malformed (truncated) query
Am I doing something incorrectly, or am I completely wrong about how NVARCHAR(MAX) works?
The problem is with implicit conversion.
If you have Unicode/nChar/nVarChar values you are concatenating, then SQL Server will implicitly convert your string to nVarChar(4000), and it is unfortunately too dumb to realize it will truncate your string or even give you a Warning that data has been truncated for that matter!
When concatenating long strings (or strings that you feel could be long) always pre-concatenate your string building with CAST('' as nVarChar(MAX)) like so:
SET #Query = CAST('' as nVarChar(MAX))--Force implicit conversion to nVarChar(MAX)
+ 'SELECT...'-- some of the query gets set here
+ '...'-- more query gets added on, etc.
What a pain and scary to think this is just how SQL Server works. :(
I know other workarounds on the web say to break up your code into multiple SET/SELECT assignments using multiple variables, but this is unnecessary given the solution above.
For those who hit an 8000 character max, it was probably because you had no Unicode so it was implicitly converted to VarChar(8000).
Warning:
You still Cannot have a Single Unbroken Literal String Larger than 4000 (or 8000 for VarChar).
Literal Strings are those you hard-code and wrap in apostrophe's.
You must Break those Strings up or SQL Server will Truncate each one BEFORE concatenating.
I add ' + ' every 20 lines (or so) to make sure I do not go over.
That's an average of at most 200 characters per line - but remember, spaces still count!
Explanation:
What's happening behind the scenes is that even though the variable you are assigning to uses (MAX), SQL Server will evaluate the right-hand side of the value you are assigning first and default to nVarChar(4000) or VarChar(8000) (depending on what you're concatenating). After it is done Concatenating and figuring out the value (and after truncating it for you) it then converts it into (MAX) when assigning it to your variable, but by then it is too late.
Problem seems to be associated with the SET statement. I think the expression can't be more than 4,000 bytes in size. There is no need to make any changes to any settings if all you are trying to do is to assign a dynamically generated statement that is more than 4,000 characters. What you need to do is to split your assignment. If your statement is 6,000 characters long, find a logical break point and then concatenate second half to the same variable. For example:
SET #Query = 'SELECT ....' [Up To 4,000 characters, then rest of statement as below]
SET #Query = #Query + [rest of statement]
Now run your query as normal i.e. EXEC ( #Query )
To see the dynamic SQL generated, change to text mode (shortcut: Ctrl-T), then use SELECT
PRINT LEN(#Query) -- Prints out 4273, which is correct as far as I can tell
--SET NOCOUNT ON
SELECT #Query
As for sp_executesql, try this (in text mode), it should show the three aaaaa...'s the middle one being the longest with 'SELECT ..' added. Watch the Ln... Col.. indicator in the status bar at bottom right showing 4510 at the end of the 2nd output.
declare #n nvarchar(max)
set #n = REPLICATE(convert(nvarchar(max), 'a'), 4500)
SET #N = 'SELECT ''' + #n + ''''
print #n -- up to 4000
select #n -- up to max
exec sp_Executesql #n
Print truncates the varchar(MAX) to 8000, nvarchar(MAX) to 4000 chars.
But;
PRINT CAST(#query AS NTEXT)
will print the whole query.
Results to text only allows a maximum of 8192 characters.
I use this approach
DECLARE #Query NVARCHAR(max);
set #Query = REPLICATE('A',4000)
set #Query = #Query + REPLICATE('B',4000)
set #Query = #Query + REPLICATE('C',4000)
set #Query = #Query + REPLICATE('D',4000)
select LEN(#Query)
SELECT #Query /*Won't contain any "D"s*/
SELECT #Query as [processing-instruction(x)] FOR XML PATH /*Not truncated*/
Your first problem is a limitation of the PRINT statement. I'm not sure why sp_executesql is failing. It should support pretty much any length of input.
Perhaps the reason the query is malformed is something other than truncation.
The problem with creating dynamic SQL using string expression is that SQL does limit the evaluation of string expressions to 4,000 chars. You can assign a longer string to an nvarchar(max) variable, but as soon as you include + in the expression (such as + CASE ... END + ), then the expression result is limited to 4,000 chars.
One way to fix this is to use CONCAT instead of +. For example:
SET #sql = CONCAT(#sql, N'
... dynamic SQL statements ...
', CASE ... END, N'
... dynamic SQL statements ...
')
Where #sql is declared as nvarchar(max).
I have encountered the same problem today and found that beyond that 4000 character limit, I had to split the dynamic query into two strings and concatenate them when executing the query.
DECLARE #Query NVARCHAR(max);
DECLARE #Query2 NVARCHAR(max);
SET #Query = 'SELECT...' -- some of the query gets set here
SET #Query2 = '...' -- more query gets added on, etc.
EXEC (#Query + #Query2)
Use this PRINT BIG function to output everything:
IF OBJECT_ID('tempdb..#printBig') IS NOT NULL
DROP PROCEDURE #printBig
GO
CREATE PROCEDURE #printBig (
#text NVARCHAR(MAX)
)
AS
--DECLARE #text NVARCHAR(MAX) = 'YourTextHere'
DECLARE #lineSep NVARCHAR(2) = CHAR(13) + CHAR(10) -- Windows \r\n
DECLARE #off INT = 1
DECLARE #maxLen INT = 4000
DECLARE #len INT
WHILE #off < LEN(#text)
BEGIN
SELECT #len =
CASE
WHEN LEN(#text) - #off - 1 <= #maxLen THEN LEN(#text)
ELSE #maxLen
- CHARINDEX(REVERSE(#lineSep), REVERSE(SUBSTRING(#text, #off, #maxLen)))
- LEN(#lineSep)
+ 1
END
PRINT SUBSTRING(#text, #off, #len)
--PRINT '#off=' + CAST(#off AS VARCHAR) + ' #len=' + CAST(#len AS VARCHAR)
SET #off += #len + LEN(#lineSep)
END
Source:
https://www.richardswinbank.net/doku.php?id=tsql:print_big
I was creating a JSON-LD to create a site review script.
**DECLARE #json VARCHAR(MAX);** The actual JSON is about 94K.
I got this to work by using the CAST('' AS VARCHAR(MAX)) + #json, as explained by other contributors:-
so **SET #json = CAST('' AS VARCHAR(MAX)) + (SELECT .....**
2/ I also had to change the Query Options:-
Query Options -> 'results' -> 'grid' -> 'Maximum Characters received' -> 'non-XML Data' SET to 2000000.
(I left the 'results' -> 'text' -> 'Maximum number of characters displayed in each column' as the default)

Dynamic Declare statements SQL Server

I'm using the varchar(MAX) value for text but as I'm building up the huge SQL it cuts the ending off.
Is there any way I can create a Dynamic Declare statement that I can then join together with others when executing the sql?
e.g. something like:
DECLARE #sSQLLeft + Convertvarchar(4),#index) varchar(MAX)
varchar(max) is up to about 2GB are you sure it cuts the ending off or is it just when you print it it only displays the first few hundred characters?
To View long text in SSMS without it getting truncated you can use this trick
SELECT #dynsql AS [processing-instruction(x)] FOR XML PATH('')
DECLARE #query VARCHAR(MAX)
DECLARE #query2 VARCHAR(MAX)
-- Do wahtever
EXEC (#query + #query2)
EDIT:
Martin Smith is quite right. It is possible that your query cuts in print. One of the reasons of this cut is NULL value in variable or in column which concatenates with your query and make rest of the query NULL.