Managing Percentages Of Money Columns
I have a question about managing percentages of money columns in SQL Server. I have a simplified case like this:
CREATE TABLE _ROUNDERROR
(
Premium Money,
Commission Money
)
INSERT INTO _ROUNDERROR (Premium, Commission)
VALUES (1632.33, 408.08)
INSERT INTO _ROUNDERROR (Premium, Commission)
VALUES (408.08, 163.23)
When I execute the following
SELECT
*,
(Commission / Premium) AS RAWDIV,
CAST(Commission AS decimal) / CAST(Premium AS decimal) AS DECDIV,
ROUND(CAST(Commission AS decimal) /CAST(Premium AS decimal), 4) AS DECDIV4,
CAST(Commission AS float) / CAST(Premium AS float) AS FLODIV,
ROUND(CAST(Commission AS float) / CAST(Premium AS float), 4) AS FLODIV4
FROM
_ROUNDERROR
These are the results of this query:
PREMIUM COMMISSION RAWDIV DECDIV DECDIV4 FLODIV FLODIV4
--------------------- --------------------- --------------------- --------------------------------------- --------------------------------------- ---------------------- ----------------------
1632,33 408,08 0,2499 0.2500000000000000000 0.2500000000000000000 0,249998468446944 0,25
408,08 163,23 0,3999 0.3995098039215686274 0.3995000000000000000 0,399995099000196 0,4
As seen above, if I divide the money columns SQL Server is ceiling the result. So, after reading some post about, I've tried to cast as decimal both columns before dividing them, and it works fine for the first pair of values (first row). But decimal is losing precision too (in second row), and I've decided to cast as float (see second row).
OK, it's working now, but it's the best solution? Is there any side-effect? I can't change the type of the fields because is a legacy database.
Answer
The reason why decimal
isn't working for you is because you don't specify any scale and precision and so it defaults to decimal(18,0)
and instantly loses any fractional part via rounding.
CAST(1632.63 as decimal)
gives 1633 for example.
You should specify precision and scale suitable for the range that money
supports.
decimal(19,4)
would represent 922,337,203,685,477.5807
exactly though you may want to reduce the precision if your money values are never anywhere near those limits.
SELECT
*,
(Commission / Premium) AS RAWDIV,
CAST(Commission AS decimal(19,4)) / CAST(Premium AS decimal(19,4)) AS DECDIV,
CAST(Commission AS float) / CAST(Premium AS float) AS FLODIV
FROM
_ROUNDERROR
Returns
+---------+------------+--------+-----------------------+-------------------+
| Premium | Commission | RAWDIV | DECDIV | FLODIV |
+---------+------------+--------+-----------------------+-------------------+
| 1632.33 | 408.08 | 0.2499 | 0.2499984684469439390 | 0.249998468446944 |
| 408.08 | 163.23 | 0.3999 | 0.3999950990001960399 | 0.399995099000196 |
+---------+------------+--------+-----------------------+-------------------+
(certainly if you are paying commission of 922,337,203,685,477
I'd likely want a job there dependent on the currency)
Related Questions
- → I can't do a foreign key, constraint error
- → How to implement DbDongle::convertTimestamps as workaround of invalid timestamps with MySql strict
- → MySQL error "Foreign key constraint is incorrectly formed"
- → Eloquent Multitable query
- → "Laravel 5.1" add user and project with userId
- → Database backup with custom code in laravel 5 and get the data upto 10 rows from per table in database
- → Laravel 5.1 QueryException when trying to delete a project
- → Using Array in '->where()' for Laravel Query Building
- → Chaining "Count of Columns" of a Method to Single Query Builder
- → Laravel Eloquent Joining Strange query
- → convert time using mysql laravel 5
- → How to update a column after an expiration date in MySQL?
- → Foreign key constraint fails on existing key