T-SQL выбирает значения, которые соответствуют ISNUMERIC, а также находятся в пределах указанного диапазона. (плюс Linq-to-sql) - PullRequest
3 голосов
/ 01 апреля 2010

Я пытаюсь выбрать строки из таблицы, в которой один из столбцов (NVARCHAR) находится в числовом диапазоне.

SELECT ID, Value
FROM Data
WHERE ISNUMERIC(Value) = 1 AND CONVERT(FLOAT, Value) < 66.6

К сожалению, как часть спецификации SQL, предложения AND не должны замыкаться (и не используются в MSSQL Server EE 2008). Дополнительная информация: Оценивается ли короткое замыкание предложения SQL WHERE?

Моя следующая попытка состояла в том, чтобы попробовать это, чтобы увидеть, смогу ли я получить отложенную оценку CONVERT

SELECT ID, Value
FROM Data
WHERE (CASE WHEN ISNUMERIC(Value) = 1 THEN CONVERT(FLOAT, Value) < 66.6 ELSE 0 END)

но я не могу использовать <(или любое сравнение) с результатом преобразования. Сбой с ошибкой </p>

Incorrect syntax near '<'.

Я могу сойти с рук

SELECT ID, CONVERT(FLOAT, Value) AS Value
FROM Data
WHERE ISNUMERIC(Value) = 1

Таким образом, очевидное решение состоит в том, чтобы обернуть весь оператор выбора в другой SELECT и WHERE и вернуть преобразованные значения из внутреннего выбора и отфильтровать там, где внешний выбор. К сожалению, именно здесь возникает проблема с Linq-to-sql. Я фильтрую не только по одному диапазону, но и по потенциальности по многим, или просто по наличию записи (есть некоторые выборки и сравнения диапазонов дат, которые я пропустил. )

По сути, я хотел бы иметь возможность генерировать что-то вроде этого:

SELECT ID, TypeID, Value
FROM Data
WHERE (TypeID = 4 AND ISNUMERIC(Value) AND CONVERT(Float, Value) < 66.6) 
      OR (TypeID = 8 AND ISNUMERIC(Value) AND CONVERT(Float, Value) > 99)
      OR (TypeID = 9)

(С некоторыми другими предложениями в каждом из этих вариантов). Это явно не сработает, если я отфильтрую не-ISNUMERIC значения во внутреннем выборе.

Как я уже говорил, я использую Linq-to-sql (и PredicateBulider) для создания этих запросов, но, к сожалению,

Datas.Where(x => ISNUMERIC(x.Value) ? Convert.ToDouble(x.Value) < 66.6 : false)

Преобразуется в это, что не решает исходную проблему.

WHERE (ISNUMERIC([t0].[Value]) = 1) AND ((CONVERT(Float,[t0].[Value])) < @p0)

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

1 Ответ

8 голосов
/ 01 апреля 2010

Не думаю, что проблема в самом AND, а скорее в преобразовании NVARCHAR в FLOAT

Посмотрите на следующий пример

DECLARE @Table TABLE(
        Value NVARCHAR(10)
)

INSERT INTO @Table SELECT '1'
INSERT INTO @Table SELECT '100'
INSERT INTO @Table SELECT 'A'

SELECT  *
FROM    @Table
WHERE   ISNUMERIC(Value)= 1 AND CAST(CAST(Value AS VARCHAR(10)) AS FLOAT) > 50

SELECT  *
FROM    @Table
WHERE   ISNUMERIC(Value)= 1 AND CAST(Value AS FLOAT) > 50

Последний выбор, где я получаю сообщение об ошибке

Сообщение 8114, уровень 16, состояние 5, строка 13 Ошибка преобразования типа данных nvarchar в плавать.

Но первый выбор работает нормально.

...