This SQL Fiddle shows the problem. Neither version is guaranteed to work. If you swap the order of the conditions in the and
then you'll get a conversion failure.
The reason the and
version happens to work in this case is because of short-circuiting. When the first condition fails, the second doesn't get run. This is an optimization that SQL Server can take advantage of. And does in this case, so you think it works.
The CTE version doesn't work because there is no guarantee on the ordering of the operations. And SQL Server decides to do something different. Namely, it tries to evaluate 'apple'
as a date.
The right solution for both is to cast before the compare. Because the cast
may not work, you need to be careful. You should use case
in SQL Server for this purpose; it is the only construct that guarantees sequential evaluation.
So, try this:
;WITH CTE AS
(
SELECT *
FROM DatesToValidate
WHERE I NOT IN ( SELECT ID
FROM Errors)
)
SELECT *
FROM CTE
WHERE (case when isdate(IDate) = 1 then cast(IDate as date)
end) NOT IN ( SELECT VDate
FROM ValidDate)