简体   繁体   中英

How to round a column defined as float on INSERT and UPDATE in SQL Server 2005

I am working on a database that uses the float data type to store values that should only be two decimal positions (dollars and cents).

Using float appears to work OK, as long as the person updating the float column does a ROUND. Of course, this does not always happen and then when a SUM is done it is always off a few pennies from what is displayed because the display is formatted to show only two decimal positions. This database has hundreds of tables using float and it would be helpful to be able to automatically ROUND the float columns.

Can this be done?

Can a TRIGGER be used on INSERT and UPDATE to do a ROUND on the Column?

If it can, could you show how you would code the TRIGGER and would you recommend it?

Any other ideas?

We are using SQL Server 2005 .

Here is a post that asks the question, Use Float or Decimal for Accounting Application Dollar Amount? , and I like the one response that said

"You should really consider using some type of fixed point / arbitrary-precision number package (eg, Java BigNum, python decimal module) otherwise you'll be in for a world of hurt ".

You can do triggers, and this is not an unreasonable use of them at all. A pre-insert and pre-update trigger should work fine.

In addition, you can do a one-shot fix, something like:

update tbl set column = round(column * 100) / 100

The syntax may not be perfect, but you should get the idea.

But I'm not sure I understand your "off by a few pennies" remark. You would have to sum a rather large number of floats for the errors to accumulate to 0.01. What is the column definition you're using?

Of course, one of the money-type decimal column definitions would be better for perfect accuracy, but you may lose portability between DBMS'.

If you have control over the system, are you able to used the DECIMAL /MONEY/NUMERIC data type instead of a FLOAT?

It is, after all, the point of the question you referenced.

If not, and like many of us you are forced to live in that world of pain, your triggers suggestion would work. I would prefer, however, to control that in a different way...
- Don't allow apps or users direct write access to the tables
- Force access through SPs

I have also seen a system where write access is given to one (input/holding) table. This table then has a trigger on it to copy (and format/validate) the data into the real table.

I don't think you can get exactly what you want by rounding. Rounding a float won't work accurately and dependably: whatever you do, you're going to be trying to apply a decimal rounding to a binary number and that just isn't going to be exact for anything but a power of 2.

You can only get accurate database-stored decimal representations of arbitrary sub-integer quantities by using a decimal datatype that's expressly designed for the purpose. These datatypes typically utilise some form of packed-decimal storage (so less efficient than binary) where, for example 2009 is stored as 0x2009 .

What happens if you use the CONVERT function? Have you tried querying using something like this?

CONVERT(money, your_float_column)

Long-term, I think I'd consider adding a column to my table that has the desired type and maintaining its value through post-insert/update triggers, then over time switch all my code to use that column instead.

Then I'd hunt down and punish the individuals who thought it was a good idea to store money amounts in a float...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM