4

我正在尝试从 (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)

但我似乎无法将 < (或任何比较)与 CONVERT 的结果一起使用。它因错误而失败

Incorrect syntax near '<'.

我可以逃脱

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

因此,显而易见的解决方案是将整个 select 语句包装在另一个 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)

(在每个 where 选项中都有一些其他子句。)如果我在内部选择中过滤掉非 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)

对于每个比较,我最后的手段必须是针对同一张表上的双重选择进行外部连接,但这并不是一个真正的想法解决方案。我想知道是否有人以前遇到过类似的问题?

4

1 回答 1

8

我不认为问题是 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 转换为浮点数时出错。

但是第一个选择工作正常。

于 2010-04-01T04:31:08.727 回答