Why does round(143.23,-1) return 140? - sql

For the query
SELECT round(143.23, -1)
FROM dual
I thought that the output will be 142 but the output i got is 140
can anyone help me by explaining this.

The second parameter indicates how many digits of precision after the decimal point you want to preserve. Thus, -1 means one digit before the decimal point. I.e., you're losing the "ones" digit and rounding to the nearest "tens", resulting in 140.
To get a whole number (143 in this case), you can pass 0 as the second parameter, or just omit it entirely, as that's the default.

Related

Number format SQL INSERT

I have created a table where a column has the format NUMBER(2,3).
I try to insert the value 5.73 but it doesn't work.
The error is :
ORA-01438 - "value larger than specified precision allowed for this column"
Cause: When inserting or updating records, a numeric value was entered
that exceeded the precision defined for the column.*
I read the documentation but i don't understand the scale.
So, what is the format accepted value 0-99 with 3 values ​​after the decimal point ?
Thanks.
You are misunderstanding precision and scale. You have a number with a precision of 2. That means that there are two significant digits. It has a scale of 3, which means that these are to the right of the decimal point.
So, your column can represent values between 0.000 and 0.099
What you want is NUMERIC(5, 3). "precision - scale" is the number of digits to the left of the decimal point.
This has come from here:
https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT1832
Optionally, you can also specify a precision (total number of digits) and scale (number of >digits to the right of the decimal point):
column_name NUMBER (precision, scale)
So in your example you are allowed a total number of 2 digits ( and 3 digits to the right of the decimal point). Which doesn't work for 5.73, perhaps you need a type of number(3,2) which would allow 3 digits 2 of which can be right of the decimal point.

What is the difference between MOD and REMAINDER in oracle?

Although both the functions perform the same operation, even they produce same o/p, what is basic difference between these two? Is there any performance related difference, if yes, then which one is better?
Thanks
The documentation is pretty clear on the difference:
NOTE
The REMAINDER function uses the round function in its formula, whereas
the MOD function uses the floor function in its formula.
In other words, when the arguments are positive integers, the mod function returns a positive number between 0 and the second argument. The remainder function returns a number whose absolute value is less than the second argument divided by 2.
The differences can be more striking for negative numbers. One example of a difference is:
REMAINDER(-15, 4)
MOD(-15, 4)
The first gives -3 and the second 1.
EDIT:
What is happening here? How many times does 4 go into -15. One method is "-4" times with a remained of 1. That is: -15 = 4*(-4) + 1. The other is "-3" times: -15 = 4*(-3) - 3.
The difference what is -15/4 expressed as an integer. Using floor, you get -4. Using round, you get -3.
The difference between MOD and REMAINDER function can be understood in the example below:
MOD(13,5): returns 3 whereas, REMAINDER (13,5) returns -2
A simple way to understand the difference is that MOD uses the floor function therefore it counts the occurrence of the second number within the first and returns what is left to complete the first number i.e. 2(5) gives 10 adding 3 gives 13 therefore MOD(13,5)=3
However, the REMAINDER uses a Round function it therefore gets the total number of the second number that could make up the first and then subtract the what makes it excess. i.e. 3(5) = 15 and subtracting 2 gives 13,therefore REMAINDER(13,5)= -2
REMAINDER (-15, 4): 4(-4) gives -16 and adding +1 gives -15 hence REMAINDER (-15,4)=+1
MOD (-15, 4): 3(-4) gives -12, adding -3 gives us -15 hence MOD(15,4)=-3
REMAINDER(-15, 4)--uses round without taking the sign of the number into
consideration.
hence -15/4= -3.75==> round(-3.75)= -4.--(ignore sign during round)
-4*4= -16
-15-(-16)=>1
There fore: REMAINDER(-15, 4)=1
MOD(-15, 4)----uses Floor without taking the sign of the number into
consideration.
-15/4= -3.75==> floor(-3.75)= -3.--(ignore sign in floor)
-3*4=-12
-15-(-12)=>-3
There fore: MOD(-15, 4)= -3
Mod(m,n) is so simple to understand.
Finding Value Mod() output value will always be the manually calculated remainder value when we divide m by n.
Finding Sign The sign of the output remains the same as the first parameter.
eg :
eg 1 : mod (11,3) is the remainder of 11/3 which is 2 and the same sign of 1st parameter. So output is 2
eg 2 : mod (-11,3) is the remainder of 11/3 which is 2 and the same sign of the 1st parameter. So the output is -2
Remainder(m,n) is a bit different
Finding Value You take two multiples of n, such that when multiplied gives the closest lower value and the closest upper value compared to the first parameter(m). The minimum difference between these values will be the output value
Finding Sign The sign of the output value will always be positive if the closest value is less than the first parameter and the if the closest value is greater than the 1st parameter then it will be negative.
eg :
eg 1 : remainder(10,3) The closest multiple values of 3 which are lesser and greater than 10 are 9(3x3) and 12(3x4). And the closest to 10 among 9 & 12 is 9. So the output will be the gap between 9 and 10 which is 1. The closest number is less than the 1st parameter. So the output is 1.
eg 2 : remainder(11,3) The closest multiple values of 11 which are lesser and greater than 11 are 9(3x3) and 12(3x4). And the closest to 12 among 9 & 12 is 12. So the output will be the gap between 12 and 11 which is 1. The closest number is greater than the 1st parameter. So the output is -1.
The question has long had an answer, but I thought some context would be helpful.
https://en.wikipedia.org/wiki/Modulo_operation discusses the “modulo” operation, and the fact that it is based on the remainder after integer division. The problem is that the concept of “remainder” is not clearly defined where there are negative numbers.
Where negative numbers are involved, the difference between modulus and remainder is significant. Mathematically, the modulus operation maps an integer on to a range. This range begins at 0 and is cyclic. For example integer mod 3 is mapped on to the range:
0, 1, 2, 0, 1, 2, …
If the given integer is negative, the cycle is simply extended backwards. If, however, the modulus itself is negative, then the whole range is negative:
0, -2, -1, 0, -2, -1, …
https://rob.conery.io/2018/08/21/mod-and-remainder-are-not-the-same/ illustrates this as a clock with negative numbers.
The practical upshot of this is that the sign of the second number is the same as the sign of the result.
With a remainder, however, you attempt to divide the second number into the first number until you can’t go any more. The remaining difference is called the remainder. If the first number is negative, then, if you stop short, the remainder will be negative.
The practical upshot of which is that the sign of the first number is the sign of the result.
Most coding languages, including most variations of SQL, use a remainder calculation, but very often call it the modulus. And most languages use the notation a % b meaning a mod b.
Oracle, of course, has two functions, which should have been helpful. However, the first function, mod(), actually gives what everybody else calls the remainder. The second, remainder() gives a result which nobody else gives, due to the fact that it is focused on the nearest division. As per the documentation, the mod() functions uses the floor() function, while remainder() uses round().
If you want to compare the results, you can try:
SELECT
remainder(19,5) AS "Remainder ++",
remainder(-19,5) AS "Remainder -+",
remainder(19,-5) AS "Remainder +-",
remainder(-19,-5) AS "Remainder --",
mod(19,5) AS "Mod ++",
mod(-19,5) AS "Mod -+",
mod(19,-5) AS "Mod +-",
mod(-19,-5) AS "Mod --",
mod(mod(19,5) + 5,5) AS "Modulo ++",
mod(mod(-19,5) + 5,5) AS "Modulo ++",
mod(mod(19,-5) + -5,-5) AS "Modulo ++",
mod(mod(-19,-5) + -5,-5) AS "Modulo ++"
FROM DUAL
;
The modulo calculation gives the true modulus, according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder
In all, you probably want the remainder as the most natural interpretation, and so you will use mod() to get this result.

Error taking int of logs in VBA

When I calculate log(8) / log(2) I get 3 as one would expect:
?log(8)/log(2)
3
However, if I take the int of this calculation like this the result is 2 and thus wrong:
?int(log(8)/log(2))
2
How and why does this happen?
Likely because the actual number returned is of type double. Because floats and doubles cannot accurately represent most base 10 rational numbers the number returned is something like 2.99999999999. Then when you apply int() the .999999999 is truncated.
How floating-point number works: it dedicates a bit for the sign, a few bits to store an exponent, and the rest for the actual fraction. This leads to numbers being represented in a form similar to 1.45 * 10^4; except that instead of the base being 10, it's two.

Number format in Oracle SQL

I've given a task of exporting data from an Oracle view to a fixed length text file, however I've been given specification of how data should be exported to a text file. I.e.
quantity NUM (10)
price NUM (8,2)
participant_id CHAR (3)
brokerage NUM (10,2)
cds_fees NUM (8,2)
My confusion arises in Numeric types where when it says (8,2). If I'm to use same as text, does it effectively means
10 characters (as to_char(<field name>, '9999999.99'))
or
8 characters (as to_char(<field name>, '99999.99'))
when exporting to fixed length text field in the text file?
I was looking at this question which gave an insight, but not entirely.
Appreciate if someone could enlighten me with some examples.
Thanks a lot.
According to the Oracle docs on types
Optionally, you can also specify a precision (total number of digits)
and scale (number of digits to the right of the decimal point):
If a precision is not specified, the column stores values as given. If
no scale is specified, the scale is zero.
So in your case, a NUMBER(8,2), has got:
8 digits in total
2 of which are after the decimal point
This gives you a range of -999999.99 to 999999.99
I assume that you mean NUMBER data type by NUM.
When it says NUMBER(8,2), it means that there will be 8 digits, and that the number should be rounded to the nearest hundredth. Which means that there will be 6 digits before, and 2 digits after the decimal point.
Refer to oracle doc:
You use the NUMBER datatype to store fixed-point or floating-point
numbers. Its magnitude range is 1E-130 .. 10E125. If the value of an
expression falls outside this range, you get a numeric overflow or
underflow error. You can specify precision, which is the total number
of digits, and scale, which is the number of digits to the right of
the decimal point. The syntax follows:
NUMBER[(precision,scale)]
To declare fixed-point numbers, for which you must specify scale, use
the following form:
NUMBER(precision,scale)
To declare floating-point numbers, for which you cannot specify
precision or scale because the decimal point can "float" to any
position, use the following form:
NUMBER
To declare integers, which have no decimal point, use this form:
NUMBER(precision) -- same as NUMBER(precision,0)
You cannot use constants or variables to specify precision and scale;
you must use integer literals. The maximum precision of a NUMBER value
is 38 decimal digits. If you do not specify precision, it defaults to
38 or the maximum supported by your system, whichever is less.
Scale, which can range from -84 to 127, determines where rounding
occurs. For instance, a scale of 2 rounds to the nearest hundredth
(3.456 becomes 3.46). A negative scale rounds to the left of the
decimal point. For example, a scale of -3 rounds to the nearest
thousand (3456 becomes 3000). A scale of 0 rounds to the nearest whole
number. If you do not specify scale, it defaults to 0.
NUMBER(p,s)
p(precision) = length of the number in digits
s(scale) = places after the decimal point
So Number(8,2) in your example is a '999999.99'
You can see more examples here.

Why decimal behave differently?

I am doing this small exercise.
declare #No decimal(38,5);
set #No=12345678910111213.14151;
select #No*1000/1000,#No/1000*1000,#No;
Results are:
12345678910111213.141510
12345678910111213.141000
12345678910111213.14151
Why are the results of first 2 selects different when mathematically it should be same?
it is not going to do algebra to convert 1000/1000 to 1. it is going to actually follow the order of operations and do each step.
#No*1000/1000
yields: #No*1000 = 12345678910111213141.51000
then /1000= 12345678910111213.141510
and
#No/1000*1000
yields: #No/1000 = 12345678910111.213141
then *1000= 12345678910111213.141000
by dividing first you lose decimal digits.
because of rounding, the second sql first divides by 1000 which is 12345678910111.21314151, but your decimal is only 38,5, so you lose the last three decimal points.
because when you divide first you get:
12345678910111.21314151
then only six decimal digits are left after point:
12345678910111.213141
then *1000
12345678910111213.141
because the intermediary type is the same as the argument's - in this case decimal(38,5). so dividing first gives you a loss of precision that's reflected in the truncated answer. multiplying by 1000 first doesn't give any loss of precision because that doesn't overload 38 digits.
It's probably because you lose part of data making division first. Notice that #No has 5-point decimal precision so when you divide this number by 1000 you suddenly need 8 digits for decimal part:
123.12345 / 1000 = 0.12312345
So the value has to be rounded (0.12312) and then this value is multiply by 1000 -> 123.12 (you lose 0.00345.
I think that's why the result is what it is...
The first does #No*1000 then divides it by 1000. The intermediates values are always able to represent all the decimal places. The second expression first divides by 1000, which throws away the last two decimal places, before multiplying back to the original value.
You can get around the problem by using CONVERT or CAST on the first value in your expression to increase the number of decimal places and avoid a loss of precision.
DECLARE #num decimal(38,5)
SET #num = 12345678910111213.14151
SELECT CAST(#num AS decimal(38,8)) / 1000 * 1000