Re: Multiplying numeric(19,4) Values
- From: alexcn <alexcn@xxxxxxxxxxx>
- Date: Fri, 18 Sep 2009 08:41:50 -0700 (PDT)
Dear Hugo,
Greetings to you, long time no speak :)
Ah ha, I certainly see now why the query has been exploding: I had
misread the purpose of the NUMERIC_ROUNDABORT server options and had
reversed their true meaning in my mind. They are correctly set to
TRUE so that is why I am getting the error.
I have read your explanation and I see that it makes (as usual)
perfect sense to me now in understanding how SQL Server determines the
maximum data types when combining datatypes through multiplication. I
guess it is true, you really do learn somethign new every single day.
Best wishes,
Alex
On Sep 18, 4:30 pm, Hugo Kornelis
<h...@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx> wrote:
Hi Alex,
Thanks for providing the repro code.
(snip)
create table #test (
id int identity(1,1) not null
, baldata numeric(13,4) not null
, pricedata numeric(10,4) not null
, valuedata numeric(10,6) not null
, currencydata numeric(14,8) not null
)
insert #test (baldata, pricedata, valuedata, currencydata) values
(123456789.1234, 10451.695, 1.043544, 149.91567605)
THESE WORKS:
select *
,(baldata + pricedata + valuedata + currencydata) as tcalc
from #test
select *
,(baldata * pricedata * valuedata) as tcalc
from #test
THIS DOESNT WORK:
select *
,CAST(baldata + pricedata + valuedata + currencydata AS numeric(19,4))
as tcalc
from #test
THESE DONT WORK:
select *
,(baldata * pricedata * valuedata * currencydata) as tcalc
from #test
select *
,CAST(baldata * pricedata * valuedata * currencydata AS numeric(19,4))
as tcalc
from #test
The reason for this is how SQL Server handles precision for numeric
data. The ultimate goal is not to lose any precision. If you multiply
two numbers, and the first has 5 digits before the decimal place and the
other 3, the maximum result has (5+3=)8 digits before the decimal. (As
the maximum result is 99,999*999=99,899,001). A similar rule goes for
the digits after the decimal pace - if one number has two and the other
3, the result will have at most (2+3=)5 digits after the decimal.
So the maximum precision of the multiplication numeric(a,b)*numeric(c,d)
is numeric(a+c,b+d). And that's the base rule SQL Server applies -
except that for some reason I don't understand, one extra digit is used
so the actual result is numeric(a+c+1,b+d)
So, let's start at two:
baldata * pricedata --> numeric(13,4) * numeric(10,4) = numeric(24,8)
Add the third factor:
(baldata * pricedata) * valuedata --> (numeric(13,4) * numeric(10,4) ) *
numeric(10,6) = numeric(24,8) * numeric(10,6) = numeric(35,14).
So far no problems. All within SQL Server's allowed range. But now, we
add the fourth factor:
(the above) * currencydata --> numeric(35,14) * numeric(14,8) =
numeric(50,22).
Now we have a problem. The maximum precision is 38, and 50 is way above
that number. Books Online says that in this case, the scale is reduced
so that precision behind the decimal may be lost in favor of keeping the
integral part. That means you run the risk of losing precision. And that
is where the setting of NUMERIC_ROUNDABORT and ARITHABORT come in.
- NUMERIC_ROUNDABORT OFF: The result is rounded (if needed) and no
errors and warnings are generated.
- NUMERIC_ROUNDABORT ON and ARITHABORT OFF: A warning is generated and
NULLS are returned.
- NUMERIC_ROUNDABORT ON and ARITHABORT OFF: An error is generated and no
result set is returned.
If you add the statement SET NUMERIC_ROUNDABORT OFF at the start of your
script, you'll see that it runs fine.
--
Hugo Kornelis, SQL Server MVP
My SQL Server blog:http://sqlblog.com/blogs/hugo_kornelis- Hide quoted text -
- Show quoted text -
.
- References:
- Multiplying numeric(19,4) Values
- From: alexcn
- Re: Multiplying numeric(19,4) Values
- From: Scott Morris
- Re: Multiplying numeric(19,4) Values
- From: alexcn
- Re: Multiplying numeric(19,4) Values
- From: Hugo Kornelis
- Multiplying numeric(19,4) Values
- Prev by Date: Re: Multiplying numeric(19,4) Values
- Next by Date: Re: Multiplying numeric(19,4) Values
- Previous by thread: Re: Multiplying numeric(19,4) Values
- Next by thread: Re: Multiplying numeric(19,4) Values
- Index(es):
Relevant Pages
|