Weird string formatting with 2 vs 4 decimal places in currency field - string-formatting

I have the following piece of code. I want to format numbers with string templates. One variable has 2 decimal places, the other 4 decimal places but they represent the same number 50000 (fifty thousand).
The first number is correctly formatted (German representation) 50.000,00, the other one however is formatted as 5 million 5.000.000,00!
DATA: lv_p2 TYPE p LENGTH 9 DECIMALS 2,
lv_p4 TYPE p LENGTH 14 DECIMALS 4.
START-OF-SELECTION.
lv_p2 = '50000'.
lv_p4 = lv_p2.
SET COUNTRY 'DE'.
"This is correctly formatted as 50.000,00
WRITE |{ lv_p2 NUMBER = ENVIRONMENT CURRENCY = 'EUR' }|.
"This is on the other hand interpreted as five million! 5.000.000,00
WRITE |{ lv_p4 NUMBER = ENVIRONMENT CURRENCY = 'EUR' }|.
Is this documented somewhere? What am I doing wrong here?
EDIT:
It looks like the problem is with the addition CURRENCY. If I don't use it, then the number is correctly formatted.
WRITE |{ lv_p4 NUMBER = ENVIRONMENT }|.
or WRITE |{ lv_p4 NUMBER = ENVIRONMENT DECIMALS = 2 }|.
Anyway looks like some kind of a bug.

I believe this behaviour is documented.
ABAP Documentation - WRITE, format_options - CURRENCY cur
When CURRENCY is added:
"For data objects of type p, the decimal places determined by the
definition of the data type are ignored completely. Independently of
the actual value and without rounding, decimal separators and
thousands separators are inserted between the digits in the places
determined by cur."
Shortly: if CURRENCY is added (by WRITE), the number of decimal places is determined by the currency (in this case EUR has 2 decimal places), so the value 50.000,0000 will be 5.000.000,00. Same length (9 digits) only the number of decimals will be different.

Related

confuse SQL Server datatype decimal over 15 digit after comma

I have table with structure as follow :
Table1 (
id int NULL,
description varchar(50) null,
rate decimal(18,15) NULL
)
and when I test insert data into the table problem value like this :
insert into Table1 (id, description, rate)
values (1, 'My Room Upstair', 38397.0893181818)
and the error like this :
Msg 8115, Level 16, State 8, Line 1 Arithmetic overflow error
converting numeric to data type numeric.
But when I use Float data type the data inserted successful. But the rate value change to different value.
need advice please...
solution of decimal data type problem
The problem is that you are not using the decimal data type correctly.
The data type is defined like this decimal(a, b).
a is used to specify the amount of digits in the value. The default value is 18, but you can choose whatever number between 1, which is the minimum and 38, which is the maximum.
b is used for the amount of digits after the decimal point. The default value is 0 but you can specify choosing between the minimum and maximum, which are the same 1 and 38. b can only be specified if a is also specified. It needs to be equal or less than a.
In your example decimal(18,15), you can insert a number that is 18 digits long, 3 before and 15 after the decimal point. 38397.0893181818 has 5 digits before the decimal point, which is why you get the error. So if you need to add 38397.0893181818, you need decimal(15,10), since the number has 15 digits, 10 of which are after the decimal point.
The problem is that the decimal(a,b) parameters work according to what you need, a defines the number of total digits and b defines the number of digits of that total that will go after the decimal point.
https://learn.microsoft.com/es-es/sql/t-sql/data-types/decimal-and-numeric-transact-sql?view=sql-server-ver16

How to add leading zeros to decimal value in tsql

i have weight column in a table where weight must be inserted with following format '09.230'. Weight column is of varchar type. so value from front end comes as '9.23' it should get converted to above mentioned format i.e.(09.230). I am able to add trailing zero but adding leading zero is a problem.
This is what i have done to add trailing zero
CAST(ROUND(#Weight,3,0) AS DECIMAL (9,3))
Suppose #Weight = 6.56 output with above comes out be '6.560' but output wanted as '06.560'.
RIGHT('0'+ CONVERT(VARCHAR, CAST(ROUND(#Weight,3,0) AS DECIMAL (9,3))), 6)
This
takes your expression,
converts it to a varchar (retaining the trailing zeros, since the source data type was decimal),
adds a 0 in front of it, and
trims it to 6 characters by removing characters from the front, if needed (e.g. 012.560 -> 12.560, but 06.560 -> 06.560).
Do note, though, that this only works for numbers with at most two digits before the decimal point: 100.123 would be truncated to 00.123!

SQL Server 2008 - Having trouble understanding decimal

I need to insert numbers with decimals into a SQL Server 2008 database. It seems like decimal() is the correct data type to use, however, I'm having trouble understanding it exactly.
I found this script (scroll down for decimal):
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=95322
Which allows me to test different decimal settings against numbers, and there's some I don't understand why they pass or fail. The way I understand it, when using decimal(precision, scale), precision is the number of digits to the left of the decimal and scale is the number of digits to the right of the decimal. Using this function, I don't understand why some are passing and why some are failing.
SELECT dbo.udfIsValidDECIMAL('2511.1', 6, 3)
I have 4 digits on the left and 1 on the right, yet this fails.
SELECT dbo.udfIsValidDECIMAL('10.123456789123456789', 18, 17)
SELECT dbo.udfIsValidDECIMAL('10.123456789123456789', 18, 16)
The first one fails, the second one passes. There are 18 digits after the decimal point, so it seems like both should fail (or pass and SQL truncates the number).
Maybe I have a fundamental misunderstanding in how decimal() is supposed to work?
DECIMAL(6,3) means: 6 digits in all, 3 of which to the right of the decimal point.
So you have 3 digits before, 3 digits after the decimal point, and of course it cannot handle 2511.1 - that's got four digits to the left of the decimal point. You'd need DECIMAL(7,3) to handle that.
See the MSDN documentation on DECIMAL:
decimal[ (p[ ,s] )] and numeric[ (p[ ,s] )]
p (precision)
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 of 38. The
default precision is 18.
s (scale)
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.
Precision is the number of digits that can be stored total.
So the number to the left of the decimal will be precision - scale.
For example, your first example will fail because you are only allowing for three places to the left of the decimal:
SELECT dbo.udfIsValidDECIMAL('2511.1',6,3)
cast(10.123456789123456789 as decimal(18,17))
A precision of 18 & scale of 17 allows just 1 digit to the left of the decimal place, but there are 2 in that example.
cast(10.123456789123456789 as decimal(18,16)
Has room for 2 digits so succeeds.

sybase format results to 4 decimal places

In sybase, how do you format the result from a select statement for a numeric field, to have no commas and 4 decimal digits.
For Example:
344,500.39495 = 344500.3949
492,930,948.39 = 492930948.3900
You can convert and format a number or a float to string with the str() function.
The second parameter is the total length of the number, including the decimal point, and the third parameter is the length after decimal point.
str(yourDecimalNumber, 20, 4)
You could use ROUND ( numeric-expression, integer-expression )
numeric-expression : The number, passed to the function, to be rounded.
integer-expression : A positive integer specifies the number of significant digits to the right of the decimal point at which to round. A negative expression specifies the number of significant digits to the left of the decimal point at which to round.

What is the best way to change to a currency format?

I have a list of values such as "12000","12345","123456" that need to be converted to currency ("120.00", "123.45", "1234.56"). The only way I know is to convert the value to a string, copy the first strlen()-2 characters to one string (dollars) and the remainging two digits to another string(cents) and then write them as the following:
printf("%s.%s", dollars, cents);
printf("$%.2f", value/100);
Don't use floats for storing or representing monetary amounts. Use longs (if you need more than 4 billion cent use llongs). Its usually a good idea to represent currency in its minimum usable unit, example use 10000 to represent 100Euro). Then the correct way to format these values (assuming 100 cent to the euro or dollar) is:
printf( "%d.%02d", value/100, value%100);
Hope that makes sense...
Calculations with currency values is a complex subject but you cant go far wrong is you always aim to have a rounded answer to the nearest currency unit (cent for example) and always make sure that rounding errors are calculated for (example, to divide 1 dollar three ways you should end up with 33+33+34 or 33+33+33+1).
to prefix values less than $1.00 with 0, use:
printf( "$%0.2f", value / 100.0 );
This will result in $0.25 if value = 25

Resources