开发者

Fixing an SQL where statement that is ugly and confusing

开发者 https://www.devze.com 2022-12-30 00:55 出处:网络
I am directly querying the back-end MS SQL Server for a software package. The key field (vehicle number) is defined as alpha though we are entering numeric value in the field. There is only one except

I am directly querying the back-end MS SQL Server for a software package. The key field (vehicle number) is defined as alpha though we are entering numeric value in the field. There is only one exception to this, we place an "R" before the number when the vehicle is being retired (which means we sold it or the vehicle is junked). Assuming the users do this right, we should not run into a problem using this method. (Right or wrong isn't the issue here)

Fast forward to now. I am trying to query a subset of these vehicle numbers (800 - 899) for some special processing. By doing a range of '800' to '899' we also get 80, 81, etc. If I cast the vehicle number into an INT, I should be able to get the right range. Exce开发者_开发问答pt that these "R" vehicles are kicking me in the butt now.

I have tried where vehicleId not like 'R%' and cast(vehicleId as int) between 800 and 899 however, I get a casting error on one of these "R" vehicles.

What does work is where vehicleId not between '800' and '899' and cast(vehicleId as int) between 800 and 899', but I feel there has to be a better way and less confusing way.

I have also tried other variations with HAVING and a sub-query all producing a casting error.


This should do the trick although its untested:

where cast(replace(vehicleId,'R','') as int) between 800 and 899


Use the _ operator instead of the % operator:

WHERE vehicleId LIKE 'R8__' OR vehicleId LIKE '8__'

You may also combine them like so:

WHERE vehicleId LIKE '%8__'


There is no guarantee that the optimizer will execute these in the right order (there's currently no short-circuit evaluation in SQL):

where vehicleId not like 'R%' and cast(vehicleId as int) between 800 and 899 

So the cast can fail.

Try this:

WHERE
    CASE
        WHEN vehicleId NOT LIKE 'R%' THEN
            CAST(vehicleId as int)
        ELSE
            0
    END BETWEEN 800 AND 899 


How about this:

WHERE vehicleId BETWEEN '800' and '899' AND LEN(vehicleId) = 3

Not perfectly clean, but it would eliminate the two character matches.


where 1=
(
    case 
        when 
            vehicleId like 'R%' then 0 
        else 
            (case when cast(vehicleId as int) between 800 and 899 then 1 else 0 end) 
    end
)


I'm not sure if you wish to include the 'R%' records and whether the range of vehicleIds is variable or not, but this might help.

WHERE vehicleId LIKE '8[0-9][0-9]' 
OR vehicleId LIKE 'R8[0-9][0-9]'

If the range is a variable then you may want something like this.

WHERE CASE WHEN vehicleId LIKE 'R%' THEN CAST(SUBSTRING(vehicleId,2,99) AS INT)
    WHEN vehicleId LIKE '[0-9][0-9][0-9]' THEN CAST(vehicleId AS INT)
    END BETWEEN 800 AND 899


I do somthing like this when I'm dealing with things like this...

DECLARE @Autos Table  (
ID varchar(100)
)

Insert into @Autos (ID) values ('R1')
Insert into @Autos (ID) values ('2')
Insert into @Autos (ID) values ('3')
Insert into @Autos (ID) values ('R4')
Insert into @Autos (ID) values ('5')
Insert into @Autos (ID) values ('R52')
Insert into @Autos (ID) values ('53')
Insert into @Autos (ID) values ('R8')

Select * from @Autos
Where cast(REPLACE(ID, 'R', '0') as integer) between 2 and 55
and ID not like 'R%'

Output is,

ID
---
2
3
5
53

--Kris


OK your problem is you are trying to do a math sort on a string field.

try something like using a derived table to first exclude the nonnumerics and tehn cast the resultant data to int

select * from 
(select * from mytable where vehicleId not like 'R%')a
where cast(vehicleId as int) between 800 and 900

Well that didn't work, you could try select * from (select * from mytable where isnumeric(vehicleId)=0)a where cast(vehicleId as int) between 800 and 900

There are some issues with isnumeric, but if it works you could write an isint() function and use that instead.

0

精彩评论

暂无评论...
验证码 换一张
取 消