Transact-SQL string self-concatenate [closed] - sql

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am new in SQL and want to create some UDF function for MS SQL Server (MS SQL Server 2012), but the very simple expression is not working. I simply want to concatenate 2 strings and save the result to the 1st one:
DECLARE #ret CHAR (20)
SET #ret = '4'
SET #ret = #ret + '55'
After executing, #ret remains at 4! Why? If I introduce another variable for '4', it works. How can I overcome the problem?

That's because you use the char data type.
When you store the value '4' in a char(20), it becomes '4___________________' (20 characters long, the _ represents spaces here).
When you concatenate '4___________________' and '55' you get '4___________________55' (22 characters long).
When you store that back in the char(20) variable, it will be truncated to 20 characters, and you get '4___________________'.

When you have a CHAR(20) the first SET will actually store '4' with 19 blank characters at the end. This is because the CHAR datatype is fixed width, and will pad your data with blank characters until it gets to the size, 20 here.
When you concatenate the '55' onto the end, it will be the 21st and 22nd characters in the string, and fall off when you try to store it inside #ret, which can only hold the first 20 characters.
Using an VARCHAR will solve your problem, allowing #ret to be the exact size you require.
DECLARE #ret VARCHAR(20);
SET #ret = '4';
SET #ret = #ret + '55';

Change datatype of the variable to match what you are concatenating: instead of char use varchar

As CHAR is a fixed length string data type, so any remaining space in the field is filled with blanks.
In your scenario, SET #ret = #ret + '55' will try to store 22 character but unfortunately, the variable is already declared as 20 character long so it truncated the result back to 20 character..Hence, you'll have 20 character with truncating last 2 character i.e. '55'.
Use char data type only when you are sure about the length of data which particular char data type column have to hold....
If you use nvarchar(20) instead of char(20), it will work fine...
DECLARE #ret nvarchar (20)
SET #ret = '4'
SET #ret = #ret + '55'
See the SQLFIDDLE

try using 'cast' in your function to ensure the #ret is a string, changing your code to this works; hope this helps.
DECLARE #ret CHAR (20)
SET #ret = '4'
SET #ret = cast(#ret as varchar(1)) + '55'
Or just change CHAR(20) to NVARCHAR(20) like this:
DECLARE #ret NVARCHAR (20)
SET #ret = '4'
SET #ret = #ret + '55'

Related

data length issue from SQL Server to Oracle with non english characher

we have 2 applications. One application uses SQL Server as the backend and the other application uses Oracle.
In the first application the user can enter some information and the 2nd application gets the data from SQL Server and insert it into oracle.
The problem is that the user can enter in any language following table shows sample data
Table in SQL Server
For instance user has entered Chinese characters in address field and length is 10,
Oracle Table
Address is not inserted here because length of address exceeds to 12, in oracle special character considering as 3 length.
I want to substring character (with non english and with english). How can I achieve that? I have written function which written number of special character.
how to get only 5 charachters from #nstring
Try to define the column in Oracle as VARCHAR2(10 CHAR). That changes the length semantics from bytes to characters. So the column will be able to accept 10 characters not just 10 bytes, which might be to short if there are special characters in the string.
declare #nstring NVARCHAR(MAX)=N'理,551'
declare #lenSQL int = len(#nstring)
declare #oracleLen int = #lenSQL +(2 * [dbo].[CountNonEnglishfromString](#nstring))
declare #OracleMaxLen int = 5; -- change as per len required
declare #newString nvarchar(max);
if(#OracleMaxLen < #oracleLen)
begin
declare #olen int =0
declare #count int =1;
WHILE ( #count <= #lenSQL)
BEGIN
declare #ch nvarchar(1) =(SELECT SUBSTRING(#nstring,#count,#count) AS ExtractString);
declare #isSpecialChar int = [dbo].[CountNonEnglishfromString](#ch)
if(#isSpecialChar = 1)
begin
set #olen = #olen+3;
end
else
begin
set #olen = #olen+1;
end
if(#OracleMaxLen < #olen)
begin
break
end
set #newString =CONCAT(#newString , #ch)
set #count = #count +1
End
End
else
begin
set #newString = #nstring
end
select isnull(#newString,'') as 'new string';

SQL Server : How to use variables? [duplicate]

This question already has an answer here:
Varchar variable is not working in WHERE clause
(1 answer)
Closed 8 years ago.
I am trying the following query and it works as I expect it to
SELECT RIGHT('0000' + CAST(MAX(party_id)+1 AS VARCHAR(4)),4) FROM PARTY
The result is:
0147
But when I execute the following query so that I can store this value in a variable
DECLARE #pid varchar;
SELECT #pid = RIGHT('0000' + CAST(MAX(party_id)+1 AS VARCHAR(4)),4) FROM PARTY
SELECT #pid as party_id
it doesn't return 0147 as in the above query, instead what it returns is
0
Can anyone please tell me what I am doing wrong here?
You should always define a length when you declare a varchar !!
This
DECLARE #pid varchar;
gives you a varchar of exactly ONE character length!!
Use
DECLARE #pid varchar(20);
and your problem is solved ...
Yo have not declared size of varchar that is why it is truncating.
Set size sufficiently large to store result.
DECLARE #pid varchar(10);
SELECT #pid = RIGHT('0000' + CAST(MAX(party_id)+1 AS VARCHAR(4)),4) FROM PARTY
SELECT #pid as party_id
From SQL Server MSDN
varchar [ ( n | max ) ]
Variable-length, non-Unicode string data. n
defines the string length and can be a value from 1 through 8,000. max
indicates that the maximum storage size is 2^31-1 bytes (2 GB). The
storage size is the actual length of the data entered + 2 bytes. The
ISO synonyms for varchar are char varying or character varying.
When n is not specified in a data definition or variable declaration
statement, the default length is 1.
DECLARE #pid varchar; implies a varchar of length 1.
Try DECLARE #pid varchar(4);

Why does SQL LEN function return '1' for a string with several characters?

Simple question - why when I print the value of the #len variable in the query below would I be getting the value 1, instead of 12 (the number of characters in the specified string)?
DECLARE #string varchar
DECLARE #index int
DECLARE #len int
DECLARE #char char(1)
SET #string = 'content loop'
SET #index = 1
SET #len= LEN(#string)
print #len
Your declaration of #string is wrong. You have no length on the varchar.
Try this:
declare #string varchar(255); -- or whatever
You just learned that the default in this situation is 1.
This is clearly specified in the documentation. As a further note, MS SQL seems to make this rather complicated:
When n is not specified in a data definition or variable declaration
statement, the default length is 1. When n is not specified when using
the CAST and CONVERT functions, the default length is 30.
The right habit is to always include the length when using varchar or nvarchar.
You need to give the variable #string an actual length. Print the variable #string and it will probably return 'C'.
Becvause varChar without a length specification is taken as varChar(1)
replace varchar with varChar(30) or varChar(max)

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

returning varchar(MAX) from a function returns truncated string

I am having a strange problem. I have a function which returns a large string by concatenating several other strings.
In some cases the string is too long and is getting truncated.
For example, there is an instance when a string of length 379999 is supposed to be returned, but what I see is that the string is truncated and the length is only 65536.
I am sure that varchar(MAX) can hold a string greater that 65536, but where am I going wrong here? The function has been shown below.
[UPDATE]
this function is being used in several stored procedures, and the stored procedures are used by the crystal reports to display data.
[UPDATE END]
ALTER FUNCTION [dbo].[GetShipContSernText](
#shipContNum numeric(9)) returns Varchar(MAX) begin
declare serns cursor for
select
serial_number
from
serial_number_view
where
ship_cont_num = #shipContNum
and
template_id is null
open serns;
declare #text varchar(MAX);
declare #serialNumber nvarchar(50);
fetch next from serns into #serialNumber;
while (##FETCH_STATUS = 0)
begin
-- cannot concat a null string.
if (#text is null)
set #text = #serialNumber;
else
set #text = #text + N', ' + #serialNumber;
end
fetch next from serns into #serialNumber;
end;
close serns;
deallocate serns;
return #text;
end
Is there a reason you can't return the rows and concatenate in the code?
You are mixing varchar and nvarchar.
Also you need to use SQL Native Client to be able to use varchar(max) as a return value.
the function is indeed returning a sting more than 65536 characters, i used the LEN function and found the length to be much greater. It was the grid which was restricting the length. Now i need to find why is the crystal report truncating the string.
Bunch of thanks to Jonas :)
There is a bug in Crystal Reports which makes it interpret varchar(max) fields as varchar(255)
see here: http://www.crystalreportsbook.com/Forum/forum_posts.asp?TID=5843&PID=17503