Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

T-SQL selecting values that match ISNUMERIC and also are within a specified range. (plus Linq-to-sql)

I am trying to select rows from a table where one of the (NVARCHAR) columns is within a numeric range.

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

Unfortunately as part of the SQL spec the AND clauses don't have to short circuit (and don't on MSSQL Server EE 2008). More info: Is the SQL WHERE clause short-circuit evaluated?

My next attempt was to try this to see if I could achieve delayed evaluation of the CONVERT

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

but I cannot seem to use a < (or any comparison) with the result of a CONVERT. It fails with the error

Incorrect syntax near '<'.

I can get away with

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

So the obvious solution is to wrap the whole select statement in another SELECT and WHERE and return the converted values from the inner select and filter in there where of the outer select. Unfortunately this is where my Linq-to-sql problem comes in. I am filtering not only by one range but potentialy by many, or just by the existance of the record (there are some date range selects and comparisons I've left out.)

Essentially I would like to be able to generate something like this:

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)

(With some other clauses in each of those where options.) This clearly doesn't work if I filter out the non-ISNUMERIC values in an inner select.

As I mentioned I am using Linq-to-sql (and PredicateBulider) to build up these queries but unfortunately

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

Gets converted to this which fails the initial problem.

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

My last resort will have to be to outer join against a double select on the same table for each of the comparisons but this isn't really an idea solution. I was wondering if anyone has run into similar issues before?

like image 797
Toby Avatar asked Feb 27 '23 06:02

Toby


1 Answers

I dont think the issue is the AND itself, but rather the convertion from NVARCHAR to FLOAT

Have a look at the following example

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

The last select is where I get the error stating

Msg 8114, Level 16, State 5, Line 13 Error converting data type nvarchar to float.

But the first select works fine.

like image 72
Adriaan Stander Avatar answered Apr 29 '23 04:04

Adriaan Stander