2013-04-10 2 views
9

Почему это не работает?Внешний запрос выполняется перед внутренним запросом

select * 
from 
(
    select membership_number 
    from members 
    where membership_number not like '%[^0-9]%' 
) mem 
where cast(membership_number as int) > 2 

См. SQL Fiddle Demo.

подзапрос должен отфильтровать данные, которые не числовой, а внешний запрос литье это целое число, так что я могу найти что-нибудь> 2.

Похоже, он работает в ИНЕКЕ сначала внешний запрос. Как мне обойти это?

+0

Вы сами запустили внутренний запрос, чтобы убедиться, что он возвращает то, что вы ожидаете? – OldProgrammer

+2

Thats cool. Я никогда не слышал о SQL Fiddle раньше. – anthonybell

+0

@ OldProgrammer- Да, у меня есть, и внутренний запрос работает нормально. Я пробовал CTE, и он делает то же самое. Единственный способ, с помощью которого я могу заставить его работать, - это «выбрать членский номер участника в test_table», а затем заменить подзапрос этой таблицей. – Lock

ответ

1

Очень интересно, я попытался воспроизвести это на SQL Server и нашел следующий. Я изменил свой запрос просто чтобы убедиться, что запрос не будет терпеть неудачу, и я могу увидеть план выполнения:

select * 
from 
(
    select membership_number 
    from members 
    where membership_number not like '%[^0-9]%' 
) mem 
where membership_number > '2' 

план выполнения имеет Table Scan с предикатом:

[master].[dbo].[members].[membership_number]>'2' 
    AND NOT [master].[dbo].[members].[membership_number] like '%[^0-9]%' 

Так что это происходит потому, что Механизм SQL Optimization работает таким образом (как кто-то сказал - никто не может гарантировать вам порядок предложений). Одним из способов исправить это, вероятно, использовать IsNumeric перед тем

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 
2

Может быть, что:

select * 
from 
(
    select 
     membership_number 
    from 
     members 
    where 
     membership_number not like '%[^0-9]%' 
) mem 
where Try_Convert(int, membership_number) > 2 
+2

Это поддерживается только sql 2012, верно? –

+0

@ EthanLi да, но в вопросе не указала версию. – mkjasinski

+0

true, просто попробуйте сделать это. –

1

я до этого вопроса. Что я сделал:

1, вы можете иметь вид, который делает:

select membership_number 
    from members 
    where membership_number not like '%[^0-9]%' 

2, или использовать временную таблицу для него

3, или используйте пункт случай:

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 

не было изящного решения, но надеюсь, что это поможет

0

В комментариях объясняется, как план выполнения c (время от времени) выбирают для оценки cast до like. Заявление case может помочь в порядке оценки, но, как говорит Адамс, даже этот метод не является 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 
+1

Операторы CASE' не всегда имеют короткое замыкание: [Подключить элемент] (http://connect.microsoft.com/SQLServer/feedback/details/690017/case-coalesce-wont- always-evaluation-in-textual-order) –

+0

@AdamWenger отмечен в сообщении. +1 –

+1

@AdamWenger: в статье упоминается конкретный случай с агрегатными функциями, которые заданы для оценки сначала всегда. В вопросе OP нет агрегатной функции, поэтому это не должно быть проблемой. И, как всегда, проверить. – siride

0

Вы можете попробовать это, в следующем запросе первое условие выполняется, и если он не работает, то он не будет выполняет 2-ое условие

select 
    membership_number 
    from 
    members 
where 
isnumeric(membership_number) = 1 and 
cast(membership_number as int) > 2 

И чтобы ответить, почему ваш запрос не работает, проверьте это explanation here