Copying a varchar(max) field in a DTS Package - sql

i am using DTS to export data to text file. but some fields are of type varchar(max) and the max size i can specify is varchar(8000). Hence text is getting truncated how can i avoid this.

I am not sure, but I have some logical ways :
1) either you have to add new column, say col1 & col2. Then apply "substring" query on your data, part data into two(or more) parts, as per your requirement. Then store first part in col1, second in col2...ans so on.
2) you have to add new row, with above logic, with row1 storing first part, row2 second part and so on.
There is no other way.
Though both ways would work, but I forcibly suggest you should go with 1st way.
**
I have third solution for you, it will work>
**
You can declare **nVARCHAR(MAX)** instead of nVARCHAR(MAX)
here is an example for you:::
DECLARE #String nVARCHAR(MAX)
DECLARE #i INT
SELECT #i = 10000,#String=''
WHILE #i>0
BEGIN
SELECT #String = #String + 'A'
SET #i = #i - 1
END
SELECT LEN(#String) as Length
Output:
Length
——————–
10000
(1 row(s) affected)
LEN statement returns 10000 and it proves that varchar(max) can store more than 8000 characters.

I would try and convert it to a Text column. A text column can hold up to 2147483647 bytes of binary data.
Thanks, Andrew

Related

Dynamic SQL query cannot store more than 4000 characters not even with NVARCHAR(MAX) [duplicate]

All, I have a large (unavoidable) dynamic SQL query. Due to the number of fields in the selection criteria the string containing the dynamic SQL is growing over 4000 chars. Now, I understand that there is a 4000 max set for NVARCHAR(MAX), but looking at the executed SQL in Server Profiler for the statement
DELARE #SQL NVARCHAR(MAX);
SET #SQL = 'SomeMassiveString > 4000 chars...';
EXEC(#SQL);
GO
Seems to work(!?), for another query that is also large it throws an error which is associated with this 4000 limit(!?), it basically trims all of the SQL after this 4000 limit and leaves me with a syntax error. Despite this in the profiler, it is showing this dynamic SQL query in full(!?).
What exactly is happening here and should I just be converting this #SQL variable to VARCHAR and get on with it?
Thanks for your time.
Ps. It would also be nice to be able to print out more than 4000 chars to look at these big queries. The following are limited to 4000
SELECT CONVERT(XML, #SQL);
PRINT(#SQL);
is there any other cool way?
I understand that there is a 4000 max set for NVARCHAR(MAX)
Your understanding is wrong. nvarchar(max) can store up to (and beyond sometimes) 2GB of data (1 billion double byte characters).
From nchar and nvarchar in Books online the grammar is
nvarchar [ ( n | max ) ]
The | character means these are alternatives. i.e. you specify either n or the literal max.
If you choose to specify a specific n then this must be between 1 and 4,000 but using max defines it as a large object datatype (replacement for ntext which is deprecated).
In fact in SQL Server 2008 it seems that for a variable the 2GB limit can be exceeded indefinitely subject to sufficient space in tempdb (Shown here)
Regarding the other parts of your question
Truncation when concatenating depends on datatype.
varchar(n) + varchar(n) will truncate at 8,000 characters.
nvarchar(n) + nvarchar(n) will truncate at 4,000 characters.
varchar(n) + nvarchar(n) will truncate at 4,000 characters. nvarchar has higher precedence so the result is nvarchar(4,000)
[n]varchar(max) + [n]varchar(max) won't truncate (for < 2GB).
varchar(max) + varchar(n) won't truncate (for < 2GB) and the result will be typed as varchar(max).
varchar(max) + nvarchar(n) won't truncate (for < 2GB) and the result will be typed as nvarchar(max).
nvarchar(max) + varchar(n) will first convert the varchar(n) input to nvarchar(n) and then do the concatenation. If the length of the varchar(n) string is greater than 4,000 characters the cast will be to nvarchar(4000) and truncation will occur.
Datatypes of string literals
If you use the N prefix and the string is <= 4,000 characters long it will be typed as nvarchar(n) where n is the length of the string. So N'Foo' will be treated as nvarchar(3) for example. If the string is longer than 4,000 characters it will be treated as nvarchar(max)
If you don't use the N prefix and the string is <= 8,000 characters long it will be typed as varchar(n) where n is the length of the string. If longer as varchar(max)
For both of the above if the length of the string is zero then n is set to 1.
Newer syntax elements.
1. The CONCAT function doesn't help here
DECLARE #A5000 VARCHAR(5000) = REPLICATE('A',5000);
SELECT DATALENGTH(#A5000 + #A5000),
DATALENGTH(CONCAT(#A5000,#A5000));
The above returns 8000 for both methods of concatenation.
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
-------------------- --------------------
8000 10000
Note that #A encountered truncation.
How to resolve the problem you are experiencing.
You are getting truncation either because you are concatenating two non max datatypes together or because you are concatenating a varchar(4001 - 8000) string to an nvarchar typed string (even nvarchar(max)).
To avoid the second issue simply make sure that all string literals (or at least those with lengths in the 4001 - 8000 range) are prefaced with N.
To avoid the first issue change the assignment from
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = 'Foo' + 'Bar' + ...;
To
DECLARE #SQL NVARCHAR(MAX) = '';
SET #SQL = #SQL + N'Foo' + N'Bar'
so that an NVARCHAR(MAX) is involved in the concatenation from the beginning (as the result of each concatenation will also be NVARCHAR(MAX) this will propagate)
Avoiding truncation when viewing
Make sure you have "results to grid" mode selected then you can use
select #SQL as [processing-instruction(x)] FOR XML PATH 
The SSMS options allow you to set unlimited length for XML results. The processing-instruction bit avoids issues with characters such as < showing up as <.
Okay, so if later on down the line the issue is that you have a query that's greater than the allowable size (which may happen if it keeps growing) you're going to have to break it into chunks and execute the string values. So, let's say you have a stored procedure like the following:
CREATE PROCEDURE ExecuteMyHugeQuery
#SQL VARCHAR(MAX) -- 2GB size limit as stated by Martin Smith
AS
BEGIN
-- Now, if the length is greater than some arbitrary value
-- Let's say 2000 for this example
-- Let's chunk it
-- Let's also assume we won't allow anything larger than 8000 total
DECLARE #len INT
SELECT #len = LEN(#SQL)
IF (#len > 8000)
BEGIN
RAISERROR ('The query cannot be larger than 8000 characters total.',
16,
1);
END
-- Let's declare our possible chunks
DECLARE #Chunk1 VARCHAR(2000),
#Chunk2 VARCHAR(2000),
#Chunk3 VARCHAR(2000),
#Chunk4 VARCHAR(2000)
SELECT #Chunk1 = '',
#Chunk2 = '',
#Chunk3 = '',
#Chunk4 = ''
IF (#len > 2000)
BEGIN
-- Let's set the right chunks
-- We already know we need two chunks so let's set the first
SELECT #Chunk1 = SUBSTRING(#SQL, 1, 2000)
-- Let's see if we need three chunks
IF (#len > 4000)
BEGIN
SELECT #Chunk2 = SUBSTRING(#SQL, 2001, 2000)
-- Let's see if we need four chunks
IF (#len > 6000)
BEGIN
SELECT #Chunk3 = SUBSTRING(#SQL, 4001, 2000)
SELECT #Chunk4 = SUBSTRING(#SQL, 6001, (#len - 6001))
END
ELSE
BEGIN
SELECT #Chunk3 = SUBSTRING(#SQL, 4001, (#len - 4001))
END
END
ELSE
BEGIN
SELECT #Chunk2 = SUBSTRING(#SQL, 2001, (#len - 2001))
END
END
-- Alright, now that we've broken it down, let's execute it
EXEC (#Chunk1 + #Chunk2 + #Chunk3 + #Chunk4)
END
You mus use nvarchar text too. that's mean you have to simply had a "N" before your massive string and that's it! no limitation anymore
DELARE #SQL NVARCHAR(MAX);
SET #SQL = N'SomeMassiveString > 4000 chars...';
EXEC(#SQL);
GO
The accepted answer helped me but I got tripped up while doing concatenation of varchars involving case statements. I know the OP's question does not involve case statements but I thought this would be helpful to post here for others like me who ended up here while struggling to build long dynamic SQL statements involving case statements.
When using case statements with string concatenation the rules mentioned in the accepted answer apply to each section of the case statement independently.
declare #l_sql varchar(max) = ''
set #l_sql = #l_sql +
case when 1=1 then
--without this correction the result is truncated
--CONVERT(VARCHAR(MAX), '')
+REPLICATE('1', 8000)
+REPLICATE('1', 8000)
end
print len(#l_sql)
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, 100000)
insert #local values(cast(#p as varchar(max)))
select DATALENGTH(col) as collen, col from #local
result collen > 8000, length col value is more than 8000 chars

4000 character limit in LIKE statement

I have been getting an error in a previously working stored procedure called by an SSRS report and I have traced it down to a LIKE statement in a scalar function that is called by the stored procedure, in combination with a 7000+ NVARCHAR(MAX) string. It is something similar to:
Msg 8152, Level 16, State 10, Line 14
String or binary data would be truncated.
I can reproduce it with the following code:
DECLARE #name1 NVARCHAR(MAX) = ''
DECLARE #name2 NVARCHAR(MAX) = ''
DECLARE #count INT = 4001
WHILE #count > 0
BEGIN
SET #name1 = #name1 + 'a'
SET #name2 = #name2 + 'a'
SET #count = #count - 1
END
SELECT LEN(#name1)
IF #name1 LIKE #name2
PRINT 'OK'
What's the deal? Is there anyway around this limitation, or is it there for good reason? Thanks.
You can also reproduce it without the terrible loop:
DECLARE #name1 NVARCHAR(MAX), #name2 NVARCHAR(MAX);
SET #name1 = REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 4000);
SET #name2 = #name1;
IF #name1 LIKE #name2
PRINT 'OK';
SELECT #name1 += N'a', #name2 += N'a';
IF #name1 LIKE #name2
PRINT 'OK';
Result:
OK
Msg 8152, Level 16, State 10, Line 30
String or binary data would be truncated.
In any case, the reason is clearly stated in the documentation for LIKE (emphasis mine):
match_expression [ NOT ] LIKE pattern [ ESCAPE escape_character ]
...
pattern
Is the specific string of characters to search for in match_expression, and can include the following valid wildcard characters. pattern can be a maximum of 8,000 bytes.
And 8,000 bytes is used up by 4,000 Unicode characters.
I would suggest that comparing the first 4,000 characters is probably sufficient:
WHERE column LIKE LEFT(#param, 4000) + '%';
I can't envision any scenario where you want to compare the whole thing; how many strings contain the same first 4000 characters but then character 4001 is different? If that really is a requirement, I guess you could go to the great lengths identified in the Connect item David pointed out.
A simpler (though probably much more computationally expensive) workaround might be:
IF CONVERT(VARBINARY(MAX), #name1) = CONVERT(VARBINARY(MAX), #name2)
PRINT 'OK';
I suggest that it would be far better to fix the design and stop identifying rows by comparing large strings. Is there really no other way to identify the row you're after? This is like finding your car in the parking lot by testing the DNA of all the Dunkin Donuts cups in all the cup holders, rather than just checking the license plate.
I have the same problem right now, and I do believe my situation -where you want to compare two strings with more than 4000 characters- is a possible situation :-).
In my situation, I'm collecting a lot of data from different tables in a NVARCHAR(MAX) field in a specific table, to be able to search on that data using FullText. Keeping that table in sync, is done using the MERGE statement, converting everything to NVARCHAR(MAX).
So my MERGE statement would look like this:
MERGE MyFullTextTable AS target
USING (
SELECT --Various stuff from various tables, casting it as NVARCHAR(MAX)
...
) AS source (IndexColumn, FullTextColumn)
ON (target.IndexColumn = source.IndexColumn)
WHEN MATCHED AND source.FullTextColumn NOT LIKE target.FullTextColumn THEN
UPDATE SET FullTextColumn = source.FullTextColumn
WHEN NOT MATCHED THEN
INSERT (IndexColumn, FullTextColumn)
VALUES (source.IndexColumn, source.FullTextColumn)
OUTPUT -- Some stuff
This would produce errors because of the LIKE comparison when the FullText-data is bigger than 4000 characters.
So I created a function that does the comparison. Allthough it's not bullet proof, it works for me. You could also split data in blocks of 4000 characters, and compare each block, but for me (for now) comparing the first 4000 characters in combination with the length, is enough ...
So the Merge-statement would look like:
MERGE MyFullTextTable AS target
USING (
SELECT --Various stuff from various tables, casting it as NVARCHAR(MAX)
...
) AS source (IndexColumn, FullTextColumn)
ON (target.IndexColumn = source.IndexColumn)
WHEN MATCHED AND udfCompareTwoTexts(source.FullTextColumn, target.FullTextColumn) = 1 THEN
UPDATE SET FullTextColumn = source.FullTextColumn
WHEN NOT MATCHED THEN
INSERT (IndexColumn, FullTextColumn)
VALUES (source.IndexColumn, source.FullTextColumn)
OUTPUT -- Some stuff
And the function looks like:
ALTER FUNCTION udfCompareTwoTexts
(
#Value1 AS NVARCHAR(MAX),
#Value2 AS NVARCHAR(MAX)
)
RETURNS BIT
AS
BEGIN
DECLARE #ReturnValue AS BIT = 0
IF LEN(#Value1) > 4000 OR LEN(#Value2) > 4000
BEGIN
IF LEN(#Value1) = LEN(#Value2) AND LEFT(#Value1, 4000) LIKE LEFT(#Value2, 4000)
SET #ReturnValue = 1
ELSE
SET #ReturnValue = 0
END
ELSE
BEGIN
IF #Value1 LIKE #Value2
SET #ReturnValue = 1
ELSE
SET #ReturnValue = 0
END
RETURN #ReturnValue;
END
GO

SQL NVARCHAR and VARCHAR Limits

All, I have a large (unavoidable) dynamic SQL query. Due to the number of fields in the selection criteria the string containing the dynamic SQL is growing over 4000 chars. Now, I understand that there is a 4000 max set for NVARCHAR(MAX), but looking at the executed SQL in Server Profiler for the statement
DELARE #SQL NVARCHAR(MAX);
SET #SQL = 'SomeMassiveString > 4000 chars...';
EXEC(#SQL);
GO
Seems to work(!?), for another query that is also large it throws an error which is associated with this 4000 limit(!?), it basically trims all of the SQL after this 4000 limit and leaves me with a syntax error. Despite this in the profiler, it is showing this dynamic SQL query in full(!?).
What exactly is happening here and should I just be converting this #SQL variable to VARCHAR and get on with it?
Thanks for your time.
Ps. It would also be nice to be able to print out more than 4000 chars to look at these big queries. The following are limited to 4000
SELECT CONVERT(XML, #SQL);
PRINT(#SQL);
is there any other cool way?
I understand that there is a 4000 max set for NVARCHAR(MAX)
Your understanding is wrong. nvarchar(max) can store up to (and beyond sometimes) 2GB of data (1 billion double byte characters).
From nchar and nvarchar in Books online the grammar is
nvarchar [ ( n | max ) ]
The | character means these are alternatives. i.e. you specify either n or the literal max.
If you choose to specify a specific n then this must be between 1 and 4,000 but using max defines it as a large object datatype (replacement for ntext which is deprecated).
In fact in SQL Server 2008 it seems that for a variable the 2GB limit can be exceeded indefinitely subject to sufficient space in tempdb (Shown here)
Regarding the other parts of your question
Truncation when concatenating depends on datatype.
varchar(n) + varchar(n) will truncate at 8,000 characters.
nvarchar(n) + nvarchar(n) will truncate at 4,000 characters.
varchar(n) + nvarchar(n) will truncate at 4,000 characters. nvarchar has higher precedence so the result is nvarchar(4,000)
[n]varchar(max) + [n]varchar(max) won't truncate (for < 2GB).
varchar(max) + varchar(n) won't truncate (for < 2GB) and the result will be typed as varchar(max).
varchar(max) + nvarchar(n) won't truncate (for < 2GB) and the result will be typed as nvarchar(max).
nvarchar(max) + varchar(n) will first convert the varchar(n) input to nvarchar(n) and then do the concatenation. If the length of the varchar(n) string is greater than 4,000 characters the cast will be to nvarchar(4000) and truncation will occur.
Datatypes of string literals
If you use the N prefix and the string is <= 4,000 characters long it will be typed as nvarchar(n) where n is the length of the string. So N'Foo' will be treated as nvarchar(3) for example. If the string is longer than 4,000 characters it will be treated as nvarchar(max)
If you don't use the N prefix and the string is <= 8,000 characters long it will be typed as varchar(n) where n is the length of the string. If longer as varchar(max)
For both of the above if the length of the string is zero then n is set to 1.
Newer syntax elements.
1. The CONCAT function doesn't help here
DECLARE #A5000 VARCHAR(5000) = REPLICATE('A',5000);
SELECT DATALENGTH(#A5000 + #A5000),
DATALENGTH(CONCAT(#A5000,#A5000));
The above returns 8000 for both methods of concatenation.
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
-------------------- --------------------
8000 10000
Note that #A encountered truncation.
How to resolve the problem you are experiencing.
You are getting truncation either because you are concatenating two non max datatypes together or because you are concatenating a varchar(4001 - 8000) string to an nvarchar typed string (even nvarchar(max)).
To avoid the second issue simply make sure that all string literals (or at least those with lengths in the 4001 - 8000 range) are prefaced with N.
To avoid the first issue change the assignment from
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = 'Foo' + 'Bar' + ...;
To
DECLARE #SQL NVARCHAR(MAX) = '';
SET #SQL = #SQL + N'Foo' + N'Bar'
so that an NVARCHAR(MAX) is involved in the concatenation from the beginning (as the result of each concatenation will also be NVARCHAR(MAX) this will propagate)
Avoiding truncation when viewing
Make sure you have "results to grid" mode selected then you can use
select #SQL as [processing-instruction(x)] FOR XML PATH 
The SSMS options allow you to set unlimited length for XML results. The processing-instruction bit avoids issues with characters such as < showing up as <.
Okay, so if later on down the line the issue is that you have a query that's greater than the allowable size (which may happen if it keeps growing) you're going to have to break it into chunks and execute the string values. So, let's say you have a stored procedure like the following:
CREATE PROCEDURE ExecuteMyHugeQuery
#SQL VARCHAR(MAX) -- 2GB size limit as stated by Martin Smith
AS
BEGIN
-- Now, if the length is greater than some arbitrary value
-- Let's say 2000 for this example
-- Let's chunk it
-- Let's also assume we won't allow anything larger than 8000 total
DECLARE #len INT
SELECT #len = LEN(#SQL)
IF (#len > 8000)
BEGIN
RAISERROR ('The query cannot be larger than 8000 characters total.',
16,
1);
END
-- Let's declare our possible chunks
DECLARE #Chunk1 VARCHAR(2000),
#Chunk2 VARCHAR(2000),
#Chunk3 VARCHAR(2000),
#Chunk4 VARCHAR(2000)
SELECT #Chunk1 = '',
#Chunk2 = '',
#Chunk3 = '',
#Chunk4 = ''
IF (#len > 2000)
BEGIN
-- Let's set the right chunks
-- We already know we need two chunks so let's set the first
SELECT #Chunk1 = SUBSTRING(#SQL, 1, 2000)
-- Let's see if we need three chunks
IF (#len > 4000)
BEGIN
SELECT #Chunk2 = SUBSTRING(#SQL, 2001, 2000)
-- Let's see if we need four chunks
IF (#len > 6000)
BEGIN
SELECT #Chunk3 = SUBSTRING(#SQL, 4001, 2000)
SELECT #Chunk4 = SUBSTRING(#SQL, 6001, (#len - 6001))
END
ELSE
BEGIN
SELECT #Chunk3 = SUBSTRING(#SQL, 4001, (#len - 4001))
END
END
ELSE
BEGIN
SELECT #Chunk2 = SUBSTRING(#SQL, 2001, (#len - 2001))
END
END
-- Alright, now that we've broken it down, let's execute it
EXEC (#Chunk1 + #Chunk2 + #Chunk3 + #Chunk4)
END
You mus use nvarchar text too. that's mean you have to simply had a "N" before your massive string and that's it! no limitation anymore
DELARE #SQL NVARCHAR(MAX);
SET #SQL = N'SomeMassiveString > 4000 chars...';
EXEC(#SQL);
GO
The accepted answer helped me but I got tripped up while doing concatenation of varchars involving case statements. I know the OP's question does not involve case statements but I thought this would be helpful to post here for others like me who ended up here while struggling to build long dynamic SQL statements involving case statements.
When using case statements with string concatenation the rules mentioned in the accepted answer apply to each section of the case statement independently.
declare #l_sql varchar(max) = ''
set #l_sql = #l_sql +
case when 1=1 then
--without this correction the result is truncated
--CONVERT(VARCHAR(MAX), '')
+REPLICATE('1', 8000)
+REPLICATE('1', 8000)
end
print len(#l_sql)
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, 100000)
insert #local values(cast(#p as varchar(max)))
select DATALENGTH(col) as collen, col from #local
result collen > 8000, length col value is more than 8000 chars

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.

SQL Server - Filter field contents to numbers only

How can I copy the value of a field, but only its numbers?
I am creating a computed column for fulltext search, and I want to copy the values from my Phone Number fields (which are varchar) into it, but not with their formatting - numbers only. What is the command that would do this in my computed column formula?
Thank you!
You are going to have to write a user defined function to do this. There are several ways to do this, here is one that I found with some quick Googling.
CREATE FUNCTION dbo.RemoveChars(#Input varchar(1000))
RETURNS VARCHAR(1000)
BEGIN
DECLARE #pos INT
SET #Pos = PATINDEX('%[^0-9]%',#Input)
WHILE #Pos > 0
BEGIN
SET #Input = STUFF(#Input,#pos,1,'')
SET #Pos = PATINDEX('%[^0-9]%',#Input)
END
RETURN #Input
END
Warning: I wouldn't put this in a WHERE condition on a large table, or in a SELECT that returns millions of rows, but it will work.
Ultimately you are probably better stripping the non-numeric characters out in the UI of your app than in DB code.
Assuming there's only a couple of non-number characters, a nested replace functions do the trick:
select replace(replace(replace(col1,'-',''),'(',''),')','')
from YourTable
You can check if you caught all characters like:
select col1
from YourTable
where col1 not like '%[-()0-9]%'
(This example is checking for -, (), and numbers.)
I'd create a user-defined function that you could use in your select and where criteria, maybe something like this:
DECLARE #position int, #result varchar(50)
SET #position = 1
SET #result = ''
WHILE #position <= DATALENGTH(#input)
BEGIN
IF ASCII(SUBSTRING(#input, #position, 1)) BETWEEN 48 AND 57
BEGIN
SET #result = #result + SUBSTRING(#input, #position, 1)
END
SET #position = #position + 1
END
RETURN #result
Best of luck!
I realize this is a somewhat older question but there is no need to resort to looping for this. And these days we should try to avoid scalar functions when possible as they are not good for performance. We can leverage an inline table valued function in conjunction with the light support of regular expressions that we have in sql server. This article from Jeff Moden explains this in more detail from the perspective of why IsNumeric does not really work. http://www.sqlservercentral.com/articles/ISNUMERIC()/71512/
The gist of it is this nifty function he put together.
CREATE FUNCTION dbo.IsAllDigits
/********************************************************************
Purpose:
This function will return a 1 if the string parameter contains only
numeric digits and will return a 0 in all other cases. Use it in
a FROM clause along with CROSS APPLY when used against a table.
--Jeff Moden
********************************************************************/
--===== Declare the I/O parameters
(#MyString VARCHAR(8000))
RETURNS TABLE AS
RETURN (
SELECT CASE
WHEN #MyString NOT LIKE '%[^0-9]%'
THEN 1
ELSE 0
END AS IsAllDigits
)