'Outer query is running before inner query
Why does this not work?
select *
from
(
select membership_number
from members
where membership_number not like '%[^0-9]%'
) mem
where cast(membership_number as int) > 2
See SQL Fiddle Demo.
The subquery should filter out data that is non numeric, and the outer query is casting this to an integer so that I can look for anything > 2.
It seems like it is running the where clause of the outer query first. How do I get around this?
Solution 1:[1]
Very interesting, I tried to reproduce this on SQL Server and found next. I changed your query to simple just to make sure that query will not fail and I can see the execution plan:
select *
from
(
select membership_number
from members
where membership_number not like '%[^0-9]%'
) mem
where membership_number > '2'
Execution plan is has Table Scan with predicate:
[master].[dbo].[members].[membership_number]>'2'
AND NOT [master].[dbo].[members].[membership_number] like '%[^0-9]%'
So this is because SQL Optimization engine works in this way (as somebody said - nobody can guarantee you the order of where clauses). One of the ways to fix it probably is to use ISNUMERIC before
select *
from
(
select membership_number
from members
where membership_number not like '%[^0-9]%'
) mem
where ISNUMERIC(mem.membership_number) = 1 and cast(mem.membership_number as int) > 2
Solution 2:[2]
Maybe that:
select *
from
(
select
membership_number
from
members
where
membership_number not like '%[^0-9]%'
) mem
where Try_Convert(int, membership_number) > 2
Solution 3:[3]
I had the issue before. What I did was:
1, you can have a view which does:
select membership_number
from members
where membership_number not like '%[^0-9]%'
2, or use temp table for it
3, or use case clause:
select *
from
(
select membership_number
from members
where membership_number not like '%[^0-9]%'
) mem
where (CASE WHEN ISNUMERIC(membership_number) THEN cast(membership_number as int) ELSE 0 END) > 2
did not have a elegant solution, but hope this helps
Solution 4:[4]
The comments explain how the execution plan can (at times) choose to evaluate the cast prior to the like. A case statement can aid the order of evaluation but as Adams mentions even this method is not 100%.
select *
from members
where case
when membership_number like '%[^0-9]%' then 0
when cast(membership_number as int) > 2 then 1
else 0
end = 1
Solution 5:[5]
You can try this, in following query first condition is executed and if it fails then it won't executes 2nd condition
select
membership_number
from
members
where
isnumeric(membership_number) = 1 and
cast(membership_number as int) > 2
And to answer why your query is not working check this explanation here
Solution 6:[6]
Old query, but still relevant.
Found this trick to force subquery to be run first. Try this:
select *
from
(
select TOP (9223372036854775807) membership_number
from members
where membership_number not like '%[^0-9]%'
) mem
where cast(membership_number as int) > 2
Value 9223372036854775807 is the BIGINT max value, probably big enough for most cases.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | outcoldman |
| Solution 2 | mkjasinski |
| Solution 3 | Ethan Li |
| Solution 4 | |
| Solution 5 | Community |
| Solution 6 | JERKER |
