I have a simple SQL statement (executing on a SQL Server upgraded from 2000 to 2008 R2):
SELECT TOP (1)
DocNox = CONVERT(integer, SUBSTRING(DocNo, 2, LEN(DocNo)-1)
FROM Tbl1
WHERE
Fld1 = 19
AND Fld2 = 1
AND Fld3 = 1
AND DocNo NOT LIKE '%-%'
ORDER BY
CONVERT(integer, SUBSTRING(DocNo, 2, LEN(DocNo)-1) DESC;
Sample data (Serial is an IDENTITY
column)
Serial DocNo Fld1 Fld2 Fld3
211 A1 19 1 1
212 A2 19 1 1
213 A003 19 1 1
214 X1-C1-1 20 1 1
Executing the query produces this error message:
Error converting nvarchar value '1-C1-1' to a column of data type int.
This is unexpected because the row containing that value ought to be filtered out by the WHERE
clause before the conversion in the SELECT
and/or ORDER BY
clauses.
I have noticed that the following changes prevent the error occurring:
- Changing the condition
WHERE Fld1 = 19
- Copying the data to another table with the same structure
- Removing the
TOP (1)
- Removing the
ORDER BY
- Changing the
ORDER BY
to a different column (e.g. Serial)
But the error still occurs in the following circumstances:
- Importing the whole table to another database
- Running the same statement against a different database with the same data
I also made a change to the statistics that prevented the error but I cannot remember exactly what I did.
Can any one explain what is happening here?
Best Answer
This is normal. T-SQL does not generally specify an evaluation order. Intuitively you would evaluate the where clause first, but that does not have to be the case. SQL Server decided against that which is entirely valid.
Currently, SQL Server does not offer a construct to be 100% sure never to hit this problem. There is a 99% sure technique though: Wrap a case expression around anything that is dangerous:
This works almost always except in very few corner cases documented on Microsoft Connect. I don't have them at hand right now.