ORACLE Maximum number - oracle

If I declare in oracle a column as a number , What will be the maximum number it can be stored ?
Based on documentation:
Positive numbers in the range 1 x 10(raised)-130 to 9.99...9 x 10(raised)125 with up
to 38 significant digits
10(raised)125 is a very big number which has more than 38 digits. Will it not be stored ? If a number greater than 38 digits is stored, it will fail ? , will it save but when queried will lose precision ?
Thanks

From Oracle Doc
Positive numbers in the range 1 x 10^130 to 9.99...9 x 10^125 with up
to 38 significant digits Negative numbers from -1 x 10^130 to
9.99...99 x 10^125 with up to 38 significant digits
Test
create table tbl(clm number);
insert into tbl select power(10, -130) from dual;
insert into tbl select 9.9999*power(10, 125) from dual;
insert into tbl select 0.12345678912345678912345678912345678912123456 from dual;
insert into tbl select -1*power(10, -130) from dual;
select clm from tbl;
select to_char(clm) from tbl;
OutPut
1.000000000000000000000000000000000E-130
9.999900000000000000000000000000000E+125
.123456789123456789123456789123456789121
-1.00000000000000000000000000000000E-130

Numbers (datatype NUMBER) are stored using scientific notation
i.e. 1000000 as 1 * 10^6 i.e. you store only 1 (mantissa) and 6 (exponent)
select VSIZE(1000000), VSIZE(1000001) from dual;
VSIZE(1000000) VSIZE(1000001)
-------------- --------------
2 5
For the first number you need only 1 byte for mantissa, for the second 4 bytes (2 digist per byte).
So using NUMBER you will not get an exception while starting to loose precision.
select power(2,136) from dual;
87112285931760246646623899502532662132700
This number not exact and "filled" with zeroes (exponent). This may or may not be harmfull - consider e.g. the MOD function:
select mod(power(2,136),2) from dual;
-100
If you want to controll the precision exactly use e.g. datatype NUMBER(38,0)
select cast(power(2,136) as NUMBER(38,0)) from dual;
ORA-01438: value larger than specified precision allowed for this column

Related

What is the syntax in Oracle to round any number to the greatest/highest place value of that number?

I have a wide variety of numbers
In the ten thousands, thousands, hundreds, etc
I would like to compute the rounding to the highest place value ex:
Starting #: 2555.5
Correctly Rounded : 3000
——
More examples ( in the same report )
Given: 255
Rounded: 300
Given: 25555
Rounded: 30000
Given: 2444
Rounded: 2000
But with the Round() or Ceil() functions I get the following
Given: 2555.5
Did not want : 2556
Any ideas ??? Thank you in advance
You can combine numeric functions like this
SELECT
col,
ROUND(col / POWER(10,TRUNC(LOG(10, col)))) * POWER(10,TRUNC(LOG(10,col)))
FROM Data
See fiddle
Explanation:
LOG(10, number) gets the power you need to raise 10 to in order get the number. E.g., LOG(10, 255) = 2.40654 and 10^2.40654 = 255
TRUNC(LOG(10, col)) the number of digit without the leading digit (2).
POWER(10,TRUNC(LOG(10, col))) converts, e.g., 255 to 100.
Then we divide the number by this rounded number. E.g. for 255 we get 255 / 100 = 2.55.
Then we round. ROUND(2.55) = 3
Finally we multiply this rounded result again by the previous divisor: 3 * 100 = 300.
By using the Oracle ROUND function with a second parameter specifying the number of digits with a negative number of digits, we can simplify the select command (see fiddle)
SELECT
col,
ROUND(col, -TRUNC(LOG(10, col))) AS rounded
FROM Data
You can also use this to round by other fractions like quarters of the main number:
ROUND(4 * col, -TRUNC(LOG(10, col))) / 4 AS quarters
see fiddle
Similar to what Olivier had built, you can use a combination of functions to round the numbers as you need. I had built a similar method except instead of using LOG, I used LENGTH to get the number of non-decimal digits.
WITH
nums (num)
AS
(SELECT 2555.5 FROM DUAL
UNION ALL
SELECT 255 FROM DUAL
UNION ALL
SELECT 25555 FROM DUAL
UNION ALL
SELECT 2444 FROM DUAL)
SELECT num,
ROUND (num, (LENGTH (TRUNC (num)) - 1) * -1) as rounded
FROM nums;
NUM ROUNDED
_________ __________
2555.5 3000
255 300
25555 30000
2444 2000

Why does Float column in Oracle gets automatically rounded-off?

Why a column with datatype as Float defined in Oracle gets automatically rounded off?
Column is created as FLOAT(5).
"TRK_TARE" FLOAT(5)
Example (Value Entered -> Final Value Retained) -:
123 -> 120
1237 -> 1200
12347 -> 12000
123457 -> 120000
1234567 -> 1200000
12345678 -> 12000000
What is the difference between FLOAT & NUMBER.
Note : No modification on Trigger is present on this columns
This is because the precision of a FLOAT is measured in binary digits, from the docs:
A subtype of the NUMBER data type having precision p. A FLOAT value is represented internally as NUMBER. The precision p can range from 1 to 126 binary digits. A FLOAT value requires from 1 to 22 bytes.
If I cast 123 as a FLOAT(5) I get the same answer:
SQL> select cast(123 as float(5)) from dual;
CAST(123ASFLOAT(5))
-------------------
120
However, when casting as a FLOAT(7) the result is 123
SQL> select cast(123 as float(7)) from dual;
CAST(123ASFLOAT(7))
-------------------
123
In general, unless there is a reason for specifying a precision, don't.
You got it wrong with the type declaration. I recommend to read this chapter of the Oracle Documentation (under "Float Datatype" part).
In this example, the float value returned cannot exceed 5 binary digits. The largest decimal number that can be represented by 5 binary digits is 31. In your examples the value exceeds 31.
Therefore, the float value must be truncated so that its significant digits do not require more than 5 binary digits. For example 123 is rounded to 120, which has only two significant decimal digits, requiring only 4 binary digits.
Oracle Database uses the Oracle FLOAT datatype internally when
converting ANSI FLOAT data. Oracle FLOAT is available for you to use,
but Oracle recommends that you use
the BINARY_FLOAT and BINARY_DOUBLE datatypes instead, as they are more
robust. Refer to "Floating-Point Numbers" for more information.

Is there an algorithm that can divide a number into three parts and have their totals match the original number?

For example if you take the following example into consideration.
100.00 - Original Number
33.33 - 1st divided by 3
33.33 - 2nd divided by 3
33.33 - 3rd divided by 3
99.99 - Is the sum of the 3 division outcomes
But i want it to match the original 100.00
One way that i saw it could be done was by taking the original number minus the first two divisions and the result would be my third number. Now if i take those 3 numbers i get my original number.
100.00 - Original Number
33.33 - 1st divided by 3
33.33 - 2nd divided by 3
33.34 - 3rd number
100.00 - Which gives me my original number correctly. (33.33+33.33+33.34 = 100.00)
Is there a formula for this either in Oracle PL/SQL or a function or something that could be implemented?
Thanks in advance!
This version takes precision as a parameter as well:
with q as (select 100 as val, 3 as parts, 2 as prec from dual)
select rownum as no
,case when rownum = parts
then val - round(val / parts, prec) * (parts - 1)
else round(val / parts, prec)
end v
from q
connect by level <= parts
no v
=== =====
1 33.33
2 33.33
3 33.34
For example, if you want to split the value among the number of days in the current month, you can do this:
with q as (select 100 as val
,extract(day from last_day(sysdate)) as parts
,2 as prec from dual)
select rownum as no
,case when rownum = parts
then val - round(val / parts, prec) * (parts - 1)
else round(val / parts, prec)
end v
from q
connect by level <= parts;
1 3.33
2 3.33
3 3.33
4 3.33
...
27 3.33
28 3.33
29 3.33
30 3.43
To apportion the value amongst each month, weighted by the number of days in each month, you could do this instead (change the level <= 3 to change the number of months it is calculated for):
with q as (
select add_months(date '2013-07-01', rownum-1) the_month
,extract(day from last_day(add_months(date '2013-07-01', rownum-1)))
as days_in_month
,100 as val
,2 as prec
from dual
connect by level <= 3)
,q2 as (
select the_month, val, prec
,round(val * days_in_month
/ sum(days_in_month) over (), prec)
as apportioned
,row_number() over (order by the_month desc)
as reverse_rn
from q)
select the_month
,case when reverse_rn = 1
then val - sum(apportioned) over (order by the_month
rows between unbounded preceding and 1 preceding)
else apportioned
end as portion
from q2;
01/JUL/13 33.7
01/AUG/13 33.7
01/SEP/13 32.6
Use rational numbers. You could store the numbers as fractions rather than simple values. That's the only way to assure that the quantity is truly split in 3, and that it adds up to the original number. Sure you can do something hacky with rounding and remainders, as long as you don't care that the portions are not exactly split in 3.
The "algorithm" is simply that
100/3 + 100/3 + 100/3 == 300/3 == 100
Store both the numerator and the denominator in separate fields, then add the numerators. You can always convert to floating point when you display the values.
The Oracle docs even have a nice example of how to implement it:
CREATE TYPE rational_type AS OBJECT
( numerator INTEGER,
denominator INTEGER,
MAP MEMBER FUNCTION rat_to_real RETURN REAL,
MEMBER PROCEDURE normalize,
MEMBER FUNCTION plus (x rational_type)
RETURN rational_type);
Here is a parameterized SQL version
SELECT COUNT (*), grp
FROM (WITH input AS (SELECT 100 p_number, 3 p_buckets FROM DUAL),
data
AS ( SELECT LEVEL id, (p_number / p_buckets) group_size
FROM input
CONNECT BY LEVEL <= p_number)
SELECT id, CEIL (ROW_NUMBER () OVER (ORDER BY id) / group_size) grp
FROM data)
GROUP BY grp
output:
COUNT(*) GRP
33 1
33 2
34 3
If you edit the input parameters (p_number and p_buckets) the SQL essentially distributes p_number as evenly as possible among the # of buckets requested (p_buckets).
I've solved this problem yesterday by subtracting 2 of 3 parts from the starting number, e.g. 100 - 33.33 - 33.33 = 33.34 and the result of summing it up is still 100.

Nested cos() calculation in Oracle 10

I have table with some positive integer numbers
n
----
1
2
5
10
For each row of this table I want values cos(cos(...cos(0)..)) (cos is applied n times) to be calculated by means of SQL statement (PL/SQL stored procedures and functions are not allowed):
n coscos
--- --------
1 1
2 0.540302305868
5 0.793480358743
10 0.731404042423
I can do this in Oracle 11g by using recursive queries.
Is it possible to do the same in Oracle 10g ?
The MODEL clause can solve this:
Test data:
create table test1(n number unique);
insert into test1 select * from table(sys.odcinumberlist(1,2,5,10));
commit;
Query:
--The last row for each N has the final coscos value.
select n, coscos
from
(
--Set each value to the cos() of the previous value.
select * from
(
--Each value of N has N rows, with value rownumber from 1 to N.
select n, rownumber
from
(
--Maximum number of rows needed (the largest number in the table)
select level rownumber
from dual
connect by level <= (select max(n) from test1)
) max_rows
cross join test1
where max_rows.rownumber <= test1.n
order by n, rownumber
) n_to_rows
model
partition by (n)
dimension by (rownumber)
measures (0 as coscos)
(
coscos[1] = cos(0),
coscos[rownumber > 1] = cos(coscos[cv(rownumber)-1])
)
)
where n = rownumber
order by n;
Results:
N COSCOS
1 1
2 0.54030230586814
5 0.793480358742566
10 0.73140404242251
Let the holy wars begin:
Is this query a good idea? I wouldn't run this query in production, but hopefully it is a useful demonstration that any problem can be solved with SQL.
I've seen literally thousands of hours wasted because people are afraid to use SQL. If you're heavily using a database it is foolish to not use SQL as your primary programming language. It's good to occasionally spend a few hours to test the limits of SQL. A few strange queries is a small price to pay to avoid the disastrous row-by-row processing mindset that infects many database programmers.
Using WITH FUNCTION(Oracle 12c):
WITH FUNCTION coscos(n INT) RETURN NUMBER IS
BEGIN
IF n > 1
THEN RETURN cos(coscos(n-1));
ELSE RETURN cos(0);
END IF;
END;
SELECT n, coscos(n)
FROM t;
db<>fiddle demo
Output:
+-----+-------------------------------------------+
| N | COSCOS(N) |
+-----+-------------------------------------------+
| 1 | 1 |
| 2 | .5403023058681397174009366074429766037354 |
| 5 | .793480358742565591826054230990284002387 |
| 10 | .7314040424225098582924268769524825209688 |
+-----+-------------------------------------------+

Merge two recordset in oracle

I have following 2 recordsets :
Recordset 1:
Id isVal isVal1
1 Y N
2 Y N
Recordset 2:
Id isVal isVal1
2 N Y
3 N Y
Actual recordset required is:
Id isVal isVal1
1 Y N
2 Y Y
3 N Y
Should I use join? Can you please advice me how can I solve this?
No, you want to place the records on top of each other so you would need to use union.
select id, max(isval) as isval, max(isval1) as isval1
from ( select id, isval, isval1
from recordset1
union all
select id, isval, isval1
from recordset1
)
group by id
I use union all as you don't need to remove duplicates, for which you would remove the all.
The max works because 'Y' is "greater" than 'N'.
I'm assuming that 'Y' takes precedence over 'N' rather than values from the first record-set are less important than values from the second.

Resources