Showing posts with label differences. Show all posts
Showing posts with label differences. Show all posts

Friday, February 10, 2012

Cast - differences between SQL2000 and SQL2005

I came across a problem when migrating from SQL2000 to SQL2005.

Table1 - large table with multiple columns including columns (X21 varchar(50), Start datetime, Complete datetime)

View1 - Only returns integer values into the dwpId column

SELECT X21 AS dwpId, Start AS startDate, Complete AS endDate
FROM Table1
WHERE (X21 IS NOT NULL) AND (X21 LIKE '[0-9]%') AND
(ProjectID NOT LIKE '%_WI')

View2

SELECT cast(dwpId as int) as dwpId, startDate, endDate
FROM View1

In SQL2005, when selecting values from View2 an error is returned indicating that the statement failed when converting a varchar value to a data type int. In SQL2000, this same statement would return the appropriate rows from the view.

I dont think this is a problem with cast..

Problem is with your data, see the Select statement for Creation of view1,

If the data contains any non numerics also, It will select ex: '123A'

Modify your Select Query to fetch only Integers like this

SELECT X21 AS dwpId, Start AS startDate, Complete AS endDate
FROM Table1
WHERE (X21 IS NOT NULL) AND ISNUMERIC(X21)=1 AND
(ProjectID NOT LIKE '%_WI')
|||

IsNumeric does not guarantee that the data can be converted to an integer. IsNumeric simply gurantees that the value can be converted to 'some type' of numeric data type. There is a trick that you can use with IsNumeric to assure that you have an integer.

The following can be copy/pasted to a query analyzer window and run so that you can see the difference.

Declare @.Temp Table(Data VarChar(20))

Insert Into @.Temp Values('1')

Insert Into @.Temp Values('1.3')

Insert Into @.Temp Values('1e4')

Insert Into @.Temp Values('2d3')

Insert Into @.Temp Values('$43.3')

Insert Into @.Temp Values('abc')

Select Data, IsNumeric(Data), IsNumeric(Data + '.0e0')

From @.Temp

Only the first value is an actual integer. By adding .0e0 to the string before checking for IsNumeric, you are guaranteed to have a valid integer.

I recommend changing your query. .. And IsNumeric(X21 + '.0e0') = 1 and ...

|||

Good Suggestion, IsNumeric returns 1, If the data contains valid integer, floating point number, money or decimal type

Change the Query ,according to the mastros suggestion

|||

The problem is that SQL Server 2005 is more aggressive in terms of evaluating expressions in your query and moving them to different stages of the query plan. This might result in conversion error like in your case if the CAST gets computed before the WHERE clause checks. So there is no guarantee that the expressions in the WHERE clause will be computed first. This was true even in SQL Server 2000 except that you probably never hit it for your schema/data set. You can get the same error there also if the query plan changes.

To resolve the problem, you need to either correct your data model to represent the values correctly. Use float if your data is float - don't mix values from different domains. Or you will have to use CASE in the SELECT list to avoid the conversion problem. Note that using CASE expression is the only way to control order of execution of various expressions. See link below for more details (search for unsafe expressions):

http://msdn2.microsoft.com/en-us/library/ms143359.aspx

To summarize you have two solutions:

1. Fix your data model / schema so you represent the values in their proper domain (not float values in varchar and mixing various values in string)

2. Or modify your SELECT in the 2nd view to:

SELECT cast(CASE WHEN dwpId LIKE '[0-9]%' THEN dwpId END as int) as dwpId, startDate, endDate

FROM View1

Note that even above check is not entirely correct because not all values that have just numeric digits can be successfully converted to int. You might get overflow errors for example. You could use ISNUMERIC but that checks for integer, numeric, and money conversions so it will let more data through. So it is best you correct your schema to avoid all these issues.