Reputation: 53
Note this is my first post :)
I was working on a program and I saw some code that behaved unexpectedly. I know there is some implicit data conversions but I do not understand how it evaluates to true...
I ran the below code and it pulled 'Yes' instead of 'No' as I expected.
The code used GETDATE(). I changed it to cast today's date so the code can be ran on another day if needed just for this post.
SELECT CASE
WHEN CONVERT(VARCHAR,CAST('6/14/2016' AS DATETIME),101) BETWEEN '06/13/2014' AND '07/04/2014'
THEN 'Yes'
ELSE 'NO'
END
Can someone explain to me the how it evaluates to true?
Upvotes: 2
Views: 90
Reputation: 778
It is doing a string compare rather than a date compare. This is dangerous when the value is actually a date. it is comparing the value of each ascii character. You can use a table like this one (http://www.ascii-code.com/) to see the values of ascii characters.
06/13/2016
06/14/2016
07/04/2014
Comapare 1 column at a time. The 0's are the same. 7 is greater than 6. So 07/04/2014 is your largest value. The first 2 dates are the same until you get to the 3/4 values. 3 is less than 4. So 06/13/2016 is less than 06/14/2016.
Since the first character with a higher or lower value determines whether the string is greater or less than, it doesn't work with dates unless you format all your dates to yyyy-mm-dd format. However, it is best to compare dates as dates rather than strings
Upvotes: 0
Reputation: 22811
Finally result of convert(cast(..))
is of varchar
type. And constants in between
are strings too. So Sql server has no choice but apply string comparison.
Upvotes: 0
Reputation: 2784
You are comparing the strings as your date is converted to VARCHAR
.
And I bet the strings are sorted alphabetically. Let's test this theory:
declare @t table (a varchar(10))
insert into @t select '06/14/2016'
insert into @t select '06/13/2014'
insert into @t select '07/04/2014'
select a from @t order by a
This will output:
a
----------
06/13/2014
06/14/2016
07/04/2014
(3 row(s) affected)
Your 2016 date is the 2nd record, so it will fall between the other dates. If you want to treat those as dates, do not convert to VARCHAR
. Then the other two dates will be converted to date type implicitly:
SELECT CASE WHEN CAST('6/14/2016' AS DATETIME) BETWEEN '06/13/2014' AND '07/04/2014' THEN 'Yes' ELSE 'NO' END
will output NO that you are expecting.
PS: To avoid unpredictable results, always declare/convert to VARCHAR(n)
as VARCHAR
conversion without specifying size uses the first string it encounters to determine size of the column in the result set and the rest may be truncated.
Upvotes: 7
Reputation: 8113
Your issue is that you're comparing different data types. If you just compare dates then you won't get an issue;
SELECT CASE
WHEN CAST('6/14/2016' AS DATETIME) BETWEEN '06/13/2014'
AND '07/04/2014'
THEN 'Yes'
ELSE 'NO'
END
It looks to me as you're basically treating these as text (varchar) it's going to do it character by character;
etc etc
Upvotes: 1