Related
I am running a simple sum and conversion to currency on a NUMBER field in an Oracle database.
My query is:
select
TO_CHAR(eve.data_entry_date, 'yyyy-mm'), wtc.description as WORK_TYPE,
TO_CHAR(sum(sev.amount),'$999,999.99') AS "Total Invoice Amount"
from
EVENT eve,
SOW_EVENT sev,
WORK_TYPE_CODE wtc,
SOW_WORK_TYPE_XREF swt,
WORK_TYPE_ITEM_CODE wti
where
eve.event_number_id = sev.event_number_id
and sev.WORK_TYPE_CODE = WORK_TYPE_CODE
and sev.event_number_id = swt.event_number_id
group by
TO_CHAR(eve.data_entry_date, 'yyyy-mm'), wtc.description
The query runs successfully, however the amounts showing up in the "Total Invoice Amount" column are returning hashes like:
Year-Month WORK_TYPE Total Invoice AMount
2019-01 Physical Work ############
2019-01 Technical Work ############
I had thought I just needed to resize the column, but that didn't work. When I just run:
sum(sev.amount)
it populates the amounts, just not formatted as currency as the 'amount' column is a number column. Any idea why I am getting the hashes when I format to currency?
From the documentation:
All number format models cause the number to be rounded to the specified number of significant digits. If a value has more significant digits to the left of the decimal place than are specified in the format, then pound signs (#) replace the value. This event typically occurs when you are using TO_CHAR with a restrictive number format string, causing a rounding operation.
Your format mask needs enough digit placeholders for the highest value you expect to see. At the moment the values seem to be above a million.
How do I know the maximum value of decimal type?
For example:
decimal(5, 2)
Can you please explain the mechanism of decimal type?
The maximum possible value can be calculated using the following maths:
(10 ^ (x-y)) - (10 ^ -y)
So in your initial example
(10 ^ (5-2)) - (10 ^ -2) = 1000 - 0.01 = 999.99
I'm adding this answer as my google results took me here when trying to remind myself how to calculate the SQL friendly upper bounds of a C# decimal going into an SQL (28,10) decimal field.
999999999999999999.9999999999 by the way.
You can use an aggregate function in order to get the maximum value in a column
SELECT MAX(myColumn) AS MyColumnMax
FROM myTable
If you want to know the maximum value for each customer for instance, you can group by this customer
SELECT CustomerID, MAX(OrderAmount) AS MaxOrderAmount
FROM CustomerOrders
GROUP BY CustomerID
You can find other aggregate functions here.
If, by contrast, you are interested in range of a decimal type, then consider, that you are declaring the total number of digits and decimals. Therefore the maximum number is reached, when all these digits are 9.
So for decimal(5,2) it would be 999.99. 5 is the total number of decimals to the left and to the right of the decimal point. 2 is the number of decimals to the right of the decimal point.
The maximum possible range for decimals is -10^38 + 1 through 10^38 - 1.
What does double [3,2] mean? Is it formatting?
double [3,2] means than values can be stored with up to 3 digits in total, of which 2 digits may be after the decimal.
The maximum number of digits may be specified as the first parameter.
The maximum number of digits to the right of the decimal point is specified in the last parameter.
I'm having following columns in a table
SIZE NUMERIC(14,5)
PRICE NUMERIC(14,5)
when I perform this select query,
SELECT SIZE,
PRICE,
SIZE*PRICE AS TOTAL
FROM TNAME
I'm getting results:
1.00000 90.00000 90.0000000000
1.00000 90.00000 90.0000000000
1.00000 90.00000 90.0000000000
1.00000 100.00000 100.0000000000
1.00000 30.00000 30.0000000000
I'm wondering why the third column is returning with 10 digits after decimal point?
Also I'm getting
Arithmetic overflow error converting numeric datatype to numeric
while inserting result into another table which has the same columns with same datatype
INSERT INTO TNAME2(SIZE, PRICE, TOTAL)
SELECT
SIZE, PRICE, SIZE * PRICE AS TOTAL
FROM
TNAME
Try This.
SELECT SIZE,
PRICE,
CAST(SIZE*PRICE AS numeric(14,5))AS TOTAL
FROM TNAME
INSERT INTO TNAME2
SELECT SIZE ,
Price ,
CAST(SIZE * PRICE AS NUMERIC(15, 5))
FROM TNAME
OR
INSERT INTO TNAME2 (SIZE,Price,TOTAL)
SELECT SIZE ,
Price ,
CAST(SIZE * PRICE AS NUMERIC(15, 5)) AS TOTAL
FROM TNAME
Regarding the first question, the number of decimals, there is nothing wrong. It's the basic, everyday multiplication we learn at school: Multiplying two decimal numbers produces a number with as many decimal digits as the sum of decimal digits of the operands. The number of integer digits can be up to the sum of integer digits of the operands.
Multiplying 10.11 by 12.13 produces 122.6343. It would be VERY awkward if SQL Server broke this basic rule and arbitrarily truncated the result.
As a result, when you try to store the product in a column that accepts fewer digits, you get an overflow error. SQL Server won't change the number of digits automatically because there is no way to decide the correct action.
There are a lot of ways you can handle this, depending on the loss of precision you are willing to suffer:
Truncate the extra digits, ie throw them away, accepting up to a unit loss. This can become a LOT of money if you store totals.
Round to the desired number of digits. Sounds intuitive, but what about half-way values, ie 0.00005 in your case? Should it be 0.0001 or 0.0000? So we have
Rounding up, where 0.5 becomes 1, resulting in up to .5 loss per entry
Down, when it becomes 0, with the same loss
Round to even or odd, where you round to the nearest odd or even number, which on average produces minimal loss. While this sounds weird, it is the standard defined in IEEE 754. It's also called banker's rounding because it's used in bookkeeping to minimize losses due to truncation.
If you want to store fewer digits you need to decide whether you need to truncate the extra digits or how to round the number, then do it yourself in code.
In your case, you can use CAST to a numeric of the desired precision. This will perform rounding half up, where 0.00005 becomes 0.0001, eg:
INSERT INTO TNAME2(SIZE, PRICE, TOTAL)
SELECT
SIZE, PRICE, CAST(SIZE * PRICE as numeric(14,5)) AS TOTAL
FROM
TNAME
SQLFiddle here
This will work, assuming the number of digits doesn't exceed 14, otherwise you will have to change the type of your table field.
If you want some other kind of rounding in SQL, you will have to create your own function.
Got below useful link.
Multiplication of numerics
As per this link you can try as query as below
SELECT SIZE,
PRICE,
CAST(SIZE*PRICE AS numeric(28,5))AS TOTAL
FROM TNAME
Try this
SELECT SIZE,PRICE,CONVERT(numeric(14,5), SIZE*PRICE) AS TOTAL
FROM TNAME
Write the same query in insert, it must work
I need to do a data migration from a data base and I'm not too familiar with databases so I would like some clarification. I have some documentation that could apply to either an Oracle or a SQL database and it has a column defined as NUMBER(10,5). I would like to know what this means. I think it means that the number has 10 digits with 5 after the decimal point, but I would like clarification. Also would this be different for either SQL or Oracle?
The first number is precision the second number is scale. The equivalent in SQL Server can be as Decimal / Numeric and you could define it like so:
DECLARE #MyDec decimal(18,2)
The 18 is the max total number of decimal digits that can be stored (that is the total number of digits, for instance 123.45 the precision here is 5, while the scale is 2). The 2 is the scale and it specifies the max number of digits stored to the right of the decimal point.
See this article
Just remember the more precision the more size in storage bytes. So keep it at a minimum if possible.
p (precision)
Specifies the maximum total number of
decimal digits that can be stored,
both to the left and to the right of
the decimal point. The precision must
be a value from 1 through the maximum
precision. The maximum precision is
38. The default precision is 18.
s (scale)
Specifies the maximum number of
decimal digits that can be stored to
the right of the decimal point. Scale
must be a value from 0 through p.
Scale can be specified only if
precision is specified. The default
scale is 0; therefore, 0 <= s <= p.
Maximum storage sizes vary, based on
the precision.
Finally, it is worth mentioning that in oracle you can define a scale greater then a precision, for instance Number(3, 10) is valid in oracle. SQL Server on the other hand requires that the precision >= scale. So if you defined Number(3,10) in oracle, it would map into sql as Number(10,10).
Defining a column in Oracle as NUMBER(10,5) means that the column value can have a decimal of up to five places of precision, and ten digits in overall length. If you insert a value into the column that does not have any decimal places defined, the maximum the column will support is 10 digits. For example, these values will be supported by the column defined as NUMBER(10,5):
1234567890
12345.67890
It made validation a pain.
MySQL and SQL Server don't support the NUMBER data type - to support decimals, you're looking at using DECIMAL (or FLOAT?). I haven't looked at PostgreSQL, but I would figure it to be similar to Oracle.
In Oracle, a column defined as NUMBER(4,5) requires a zero for the first digit after the decimal point and rounds all values past the fifth digit after the decimal point.
From the Oracle documentation
NUMBER(p,s)
where: p is the precision, or the
total number of digits. Oracle
guarantees the portability of numbers
with precision ranging from 1 to 38. s
is the scale, or the number of digits
to the right of the decimal point. The
scale can range from -84 to 127.
Here are some examples :
Actual data .000127 stored in NUMBER(4,5) becomes .00013
Actual data 7456123.89 stored in NUMBER(7,-2) becomes 7456100
Edited
JonH mentions something noteworthy:
Oracle allows the scale > precision,
so SQL will map that so that if s>p
then p becomes s. That is NUMBER(3, 4)
in oracle becomes NUMERIC(4,4) in SQL.