views:

32

answers:

3

Let's say I have the following data in a decimal (18,9) identity column in a database table:

ID
========
1000.00
1001.23
1002.00
1003.23

I want to write a SQL query that returns only those records that have .230000000 for the right side of the decimal place, such that only the following are returned:

1001.23
1003.23

I know I could do this by converting it to a string a doing a string comparison, but is there a better way that doesn't involve string comparison and is more efficient at handling numeric values?


Based on Martin's answer, I think the best solution to use is like so:

Abs(ID - Cast(ID As int))

I added the Abs() function to work with negative numbers.

I ran the following tests to make sure I wasn't getting wierd rounding errors:

Declare @ID decimal(18,9)

Set @ID = 1000.000000000
Select @ID, Abs(@ID - Cast(@ID As int))
-- Returns: 1000.000000000  0.000000000

Set @ID = -1000.000000000
Select @ID, Abs(@ID - Cast(@ID As int))
-- Returns: -1000.000000000 0.000000000

Set @ID = 1000.000000001
Select @ID, Abs(@ID - Cast(@ID As int))
-- Returns: 1000.000000001  0.000000001

Set @ID = -1000.000000001
Select @ID, Abs(@ID - Cast(@ID As int))
-- Returns: -1000.000000001 0.000000001

Set @ID = 1000.999999999
Select @ID, Abs(@ID - Cast(@ID As int))
-- Returns: 1000.999999999  0.999999999

Set @ID = -1000.999999999
Select @ID, Abs(@ID - Cast(@ID As int))
-- Returns: -1000.999999999 0.999999999
+2  A: 
SELECT
    [ID]
FROM
    [TABLE]
WHERE
    [ID] - ROUND([ID], 0) = .23

HTH,
Kent

Kent Boogaart
Thanks for the idea. Is there a reason you are using `Round` versus another method? I've gotten burned by `Round` in other languages/platforms where it didn't behave exactly as I expected.
Ben McCormack
In the past I've used casts, but that just completely slipped my mind whilst answering ;)
Kent Boogaart
+2  A: 

Can you create a persisted computed column

id - cast(id as int)

So you can then index it?

Martin Smith
Thanks for the suggestion. Is there a a reason you prefer `cast` as `int` versus `Round`? I'm always scared by implicit rounding when casting. Also, good suggestion on computed column, but I'm not going to be able to add columns to this table.
Ben McCormack
@Ben - I cast as `int` as I wasn't sure if you would be dealing with decimal values >0.5 that would then get rounded up rather than down. `select 3.7 - ROUND(3.7, 0)` gives `-0.3` for example.
Martin Smith
@Martin Ok. I suppose my main concern is that I need to be able to trust that `cast` as `int` always returns the integral portion of a number by simply dropping the decimal values.
Ben McCormack
Yes that is how it works. Try `select cast(0.99999 as int), cast(1.9999 as int), cast(-.99999 as int), cast(-1.9999 as int)`
Martin Smith
@Martin that worked perfectly. I added the `Abs()` function to work with negative numbers (though I don't anticipate needing that with my ID column). I've also updated my question with some tests that prove what you were saying. Much thanks!
Ben McCormack
A: 

How about this?

SELECT MyCol
FROM MyTable
WHERE MyCol - ROUND(MyCol, 0) = .23
bobs