|
-
Jul 14th, 2009, 03:52 AM
#1
[SQL Server 2005] Mysterious problem with CASE statement
Hi,
When I perform some calcualtion in a case statement, it appends spaces randomly to the end of it. (From what I observed, it tries to make the length of the output equal to the longest possible value from all case conditions.)
sql Code:
declare @num int, @out varchar(10)
set @num = 2
set @out = case @num
when 1 then char(65)
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
The output is:
Code:
output = |AA |
length of output = 2
Notice that though the length of output is reported as 2, there are 3 spaces appended to it. So the actual length is 5.
If we repeat the same thing with constants we get the results what we expect:
sql Code:
declare @num int, @out varchar(10)
set @num = 2
set @out = case @num
when 1 then 'A'
when 2 then 'AA'
when 3 then 'AAA'
when 4 then 'AAAA'
else 'AAAAA'
end
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
The output is:
Code:
output = |AA|
length of output = 2
Notice that there are no spaces appended now. The length reported is still 2 and this is correct.
Anyone knows the reason for this behaviour and how to get past this?
Last edited by Pradeep1210; Jul 14th, 2009 at 04:12 AM.
-
Jul 14th, 2009, 07:10 AM
#2
Re: [SQL Server 2005] Mysterious problem with CASE statement
That is because you are using varchar as the datatype for @out. Remember when you decare the size of a varchar variable that is the max size the thing is not the actual size. The size used (lenght) will trim out the spaces on the end.
Sometimes the Programmer
Sometimes the DBA
Mazz1
-
Jul 14th, 2009, 12:26 PM
#3
Re: [SQL Server 2005] Mysterious problem with CASE statement
The @out variable is declared as varchar(10) in both cases. The difference is only due to whether I use the constant 'A' or function char(65). When we use 'A' to generate the output, there is no space padding. But when we use char(65) to generate that A character, it pads spaces to it.
Shouldn't it behave same in both cases?
From what I observed, It makes the total length of the @out variable equal to 5 (i.e. the maximum length possible from that CASE statement). So when @num=1, it pads 4 spaces; when @num=2, it pads 3 spaces; when @num=3 it pads 2 spaces...
Mysteriously the len(@out) returns the correct length in both cases whether spaces are padded or not.
Last edited by Pradeep1210; Jul 14th, 2009 at 01:05 PM.
-
Oct 7th, 2009, 08:29 AM
#4
Re: [SQL Server 2005] Mysterious problem with CASE statement
Long time no reply.
I wonder if anyone knows anything about this.
-
Oct 7th, 2009, 09:18 AM
#5
Re: [SQL Server 2005] Mysterious problem with CASE statement
I figured it out.... Gary was half right... just looking at the wrong place.... and the wrong variable.
It's your case... you're returning up to 5 characters.... so think about it for a sec... what would the RETURN TYPE of the CASE be? The largest possible... a char(5) type....
At first I thought that by wrapping the entire CASE in a convert (or a CAST if you prefer) would work, but that didn't seem to do much good... but if you set each of the return values to a varchar, then it seems to work as you would expect.
compare the results of
Code:
declare @num int, @out varchar(10)
set @num = 2
set @out = case @num
when 1 then char(65)
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end)
print 'output = |' + @out + '|'
print 'output = |' + REPLACE(@out,' ','*') + '|'
print 'length of output = ' + cast(len(@out) as varchar)
to this
Code:
declare @num int, @out varchar(10)
set @num = 2
set @out = case @num
when 1 then CONVERT(varchar(5), char(65) )
when 2 then CONVERT(varchar(5), char(65) + char(65))
when 3 then CONVERT(varchar(5), char(65) + char(65) + char(65))
when 4 then CONVERT(varchar(5), char(65) + char(65) + char(65) + char(65))
else CONVERT(varchar(5), char(65) + char(65) + char(65) + char(65) + char(65))
end
print 'output = |' + @out + '|'
print 'output = |' + REPLACE(@out,' ','*') + '|'
print 'length of output = ' + cast(len(@out) as varchar)
-tg
-
Oct 7th, 2009, 09:40 AM
#6
Re: [SQL Server 2005] Mysterious problem with CASE statement
Mysteriously the len(@out) returns the correct length in both cases whether spaces are padded or not.
No mystery there. The Len function ignores trailing spaces.
-
Oct 7th, 2009, 12:07 PM
#7
Re: [SQL Server 2005] Mysterious problem with CASE statement
 Originally Posted by techgnome
I figured it out.... Gary was half right... just looking at the wrong place.... and the wrong variable.
It's your case... you're returning up to 5 characters.... so think about it for a sec... what would the RETURN TYPE of the CASE be? The largest possible... a char(5) type....
At first I thought that by wrapping the entire CASE in a convert (or a CAST if you prefer) would work, but that didn't seem to do much good... but if you set each of the return values to a varchar, then it seems to work as you would expect.
...
You are right. But shouldn't it behave same with the constant 'A' test?
 Originally Posted by brucevde
No mystery there. The Len function ignores trailing spaces.
Great to know this. Thanks
-
Oct 7th, 2009, 12:08 PM
#8
Re: [SQL Server 2005] Mysterious problem with CASE statement
So I now repeated the test in a different way.
Code:
declare @num int
declare @out varchar(10)
declare @c char(1)
declare @v varchar(1)
print '== Using CHAR function =='
set @num = 0
while (@num < 5)
begin
set @num = @num + 1
set @out = case @num
when 1 then char(65)
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
end
print ''
print '== Using a constant value =='
set @num = 0
while (@num < 5)
begin
set @num = @num + 1
set @out = case @num
when 1 then 'A'
when 2 then 'A' + 'A'
when 3 then 'A' + 'A' + 'A'
when 4 then 'A' + 'A' + 'A' + 'A'
else 'A' + 'A' + 'A' + 'A' + 'A'
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
end
print ''
print '== Using a char type variable =='
set @c = 'A'
set @num = 0
while (@num < 5)
begin
set @num = @num + 1
set @out = case @num
when 1 then @c
when 2 then @c + @c
when 3 then @c + @c + @c
when 4 then @c + @c + @c + @c
else @c + @c + @c + @c + @c
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
end
print ''
print '== Using a varchar type variable =='
set @v = 'A'
set @num = 0
while (@num < 5)
begin
set @num = @num + 1
set @out = case @num
when 1 then @v
when 2 then @v + @v
when 3 then @v + @v + @v
when 4 then @v + @v + @v + @v
else @v + @v + @v + @v + @v
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
end
Result:
Code:
== Using CHAR function ==
output = |A****|
length of output = 5
output = |AA***|
length of output = 5
output = |AAA**|
length of output = 5
output = |AAAA*|
length of output = 5
output = |AAAAA|
length of output = 5
== Using a constant value ==
output = |A|
length of output = 1
output = |AA|
length of output = 2
output = |AAA|
length of output = 3
output = |AAAA|
length of output = 4
output = |AAAAA|
length of output = 5
== Using a char type variable ==
output = |A****|
length of output = 5
output = |AA***|
length of output = 5
output = |AAA**|
length of output = 5
output = |AAAA*|
length of output = 5
output = |AAAAA|
length of output = 5
== Using a varchar type variable ==
output = |A|
length of output = 1
output = |AA|
length of output = 2
output = |AAA|
length of output = 3
output = |AAAA|
length of output = 4
output = |AAAAA|
length of output = 5
This leads us to a conclusion that the confusion is on how SQL server sees a constant string of characters.
Sometimes it treats it as CHAR type while sometimes it treats it as VARCHAR type. So with our test with constants, it returns a VARCHAR in which the trailing spaces are trimmed off. But if you simply do PRINT 'A ', it prints with spaces which means CHAR type.
I was expecting a a return type of CHAR(5) with the char function as the return type of char function is char(1).
Am I right with this?
Last edited by Pradeep1210; Oct 7th, 2009 at 12:11 PM.
-
Oct 7th, 2009, 01:14 PM
#9
Re: [SQL Server 2005] Mysterious problem with CASE statement
it prints with spaces which means CHAR type.
WHACK! NO! just because it has spaces doesn't make it a char type...
if you PRINT CONVERT( char(2), 'A') .... then yes, you get the space... since you've defined it to be 2 characters long....
VarChar is like String in VB... it is a VARiable CHARacter length .... CHAR is FIXED LENGTH... Like String*5 - so when you use the type Char(5) ... you're saying. this will be 5 characters long.... no more... no less... It is a fixed size. Since you can't have an empty char string, it fills it with spaces. the Char() function explicitly returns a Char type....
I'm not sure what you were expecting with those tests you ran... they return exactly what I would expect.
-tg
-
Oct 7th, 2009, 01:18 PM
#10
Re: [SQL Server 2005] Mysterious problem with CASE statement
And no... there is no confusion... at least from my perspective.... consider this:
Code:
Dim myInt as Int32
Dim myshort as Int16
Dim myLong as Int64
Dim myDecimal as Decimal
myInt = 100
myLong = 100
myShort = 100
myDecimal = 100
Are they not the same thing? even though 100 is a "constant" it gets typed to the proper type during the assignment. We do stuff like this all the time, and it doesn't cause confusion...
-tg
-
Oct 7th, 2009, 01:29 PM
#11
Re: [SQL Server 2005] Mysterious problem with CASE statement
I won't get into the debate of why it happens but wouldn't the simplest solution be to just LTrim the entire case:-
Code:
SET @out = LTrim(case @num
when 1 then char(65)
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end)
I haven't got SQLServer in front of me to trythis but it should get round the issue.
The best argument against democracy is a five minute conversation with the average voter - Winston Churchill
Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd
-
Oct 7th, 2009, 01:40 PM
#12
Re: [SQL Server 2005] Mysterious problem with CASE statement
the spaces aren't on the left, so LTrim won't work... RTrim might... but I think you'd still run into the problem as it's going to return a CHAR(5) .... worth a try though.
-tg
-
Oct 7th, 2009, 02:39 PM
#13
Re: [SQL Server 2005] Mysterious problem with CASE statement
LTrim won't work... RTrim might...
Sorry, brain fart.
The best argument against democracy is a five minute conversation with the average voter - Winston Churchill
Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd
-
Oct 7th, 2009, 02:52 PM
#14
Re: [SQL Server 2005] Mysterious problem with CASE statement
 Originally Posted by FunkyDexter
 Sorry, brain fart.
It THAT what that smell was? Man, dude... might want to do something about that... less broccoli or something. Geezes... 
-tg
-
Oct 7th, 2009, 02:57 PM
#15
Re: [SQL Server 2005] Mysterious problem with CASE statement
 Originally Posted by techgnome
And no... there is no confusion... at least from my perspective.... consider this:
...
Are they not the same thing? even though 100 is a "constant" it gets typed to the proper type during the assignment. We do stuff like this all the time, and it doesn't cause confusion...
-tg
The confusion is: It behaves differently if there is atleast one case with a constant value. This is usually the case when we are actually using it in stored procedures etc.
Consider this:
Code:
declare @num int
declare @out varchar(10)
set @num = 3
set @out = case @num
when 1 then char(65)
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
set @out = case @num
when 1 then 'A'
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
Technically the output of these two should be same as we are not touching case 1 in either the first one or the second one. Yet output is different, based on whether at-least one of the cases is a constant value or not.
-
Oct 7th, 2009, 04:11 PM
#16
Re: [SQL Server 2005] Mysterious problem with CASE statement
It's going to go with the most flexible type.... case your 'A' to a Char(1) ... you should then get the same results again...
Code:
declare @num int
declare @out varchar(10)
set @num = 3
set @out = case @num
when 1 then char(65)
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
set @out = case @num
when 1 then 'A'
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
set @out = case @num
when 1 then CAST('A' as char(1))
when 2 then char(65) + char(65)
when 3 then char(65) + char(65) + char(65)
when 4 then char(65) + char(65) + char(65) + char(65)
else char(65) + char(65) + char(65) + char(65) + char(65)
end
set @out = replace(@out,' ','*')
print 'output = |' + @out + '|'
print 'length of output = ' + cast(len(@out) as varchar)
Results:
output = |AAA**|
length of output = 5
output = |AAA|
length of output = 3
output = |AAA**|
length of output = 5
since a varchar is more flexible than a char, then that's what it goes with in that second case.
In the first and third example, the largest thing that can come out of it is a Char(5), so that's what gets returned.
It's almost a shame that SQL doesn't have a TypeOf operator...
-tg
-
Oct 7th, 2009, 04:40 PM
#17
Re: [SQL Server 2005] Mysterious problem with CASE statement
ok.. So 'A' would be varchar(1), Isn't it?
So shouldn't the most flexible datatype still be Char(5)?
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|