You are on page 1of 9

HANDLING LARGE NUMBERS IN ORACLE

Author JP Vijaykumar, Oracle DBA


Written Dec 8th 2013
--I HAD TWO LARGE NUMBERS WITH 64 DIGITS EACH.
I WANT TO FIND THE SUM OF ALL DIGITS IN THESE NUMBERS.
(ADD ALL DIGITS IN THE NUMBER, UNTIL THE SUM OF ALL DIGITS BECOMES A SINGLE DI
GIT).
--CREATED A FUNCTION TO SUM ALL THE DIGITS.
create or replace function num_tot(i_num in number)
return number is
v_len number;
v_tot number;
v_num number:=i_num;
begin
v_len:=length(v_num);
<<WHILE_LOOP>>
v_tot:=0;
for i in 1..v_len loop
v_tot:=v_tot+substr(v_num,i,1);
end loop;
v_num:=v_tot;
v_len:=length(v_num);
if (v_len > 1) then
goto WHILE_LOOP;
end if;
return v_tot;
end;
--FINDING THE SUM OF ALL DIGITS IN THE TWO LARGE NUMBERS.
SQL> select num_tot(&num) sum_digits_in_number from dual;
Enter value for num: 53471174487509326626683734665971051554519813719210851244861
07341
old 1: select num_tot(&num) sum_digits_in_number from dual
new 1: select num_tot(53471174487509326626683734665971051554519813719210851244
86107341) sum_digits_in_number from dual
SUM_DIGITS_IN_NUMBER
-------------------2
SQL> /
Enter value for num: 53471174487509326626683734665971051554519813719210851244861
07343
old 1: select num_tot(&num) sum_digits_in_number from dual
new 1: select num_tot(53471174487509326626683734665971051554519813719210851244
86107343) sum_digits_in_number from dual
SUM_DIGITS_IN_NUMBER
--------------------

2
--THE ABOVE FUNCTION IS PRINTING THE SAME TOTAL FOR BOTH THE ABOVE LARGE NUMBERS
.
WHICH IS INCORRECT.
--WROTE AN ADHOC PROCEDURE TO HANDLE NUMBERS LARGER THAN 38 DIGITS.
SQL>
SQL>
2
3
4
5
6
7

set serverout on size 1000000 timing on


declare
v_num number:=111111111111111111111111111111111111111;
v_dgt number:=0;
v_str number;
begin
for i in 1..9 loop
begin

8
9 v_num:=replace( v_num,v_dgt,i);
10 dbms_output.put_line(length(v_num)||' '||v_num);
11 v_str:=v_num;
12 for j in 1..3 loop
13 v_str:=v_str||i;
14 dbms_output.put_line(length(v_str)||' '||v_str);
15 end loop;
16 v_dgt:=i;
17 exception
18 when others then
19
20 dbms_output.put_line(i||' '||sqlerrm);
21 end;
end loop;
22 23 end;
24 /
39 111111111111111111111111111111111111111
40 1111111111111111111111111111111111111111
41 11111111111111111111111111111111111111100
42 111111111111111111111111111111111111111000
39 222222222222222222222222222222222222222
40 2222222222222222222222222222222222222222
41 22222222222222222222222222222222222222200
42 222222222222222222222222222222222222222000
39 333333333333333333333333333333333333333
40 3333333333333333333333333333333333333333
41 33333333333333333333333333333333333333300
42 333333333333333333333333333333333333333000
39 444444444444444444444444444444444444444
40 4444444444444444444444444444444444444444
41 44444444444444444444444444444444444444400
42 444444444444444444444444444444444444444000
39 555555555555555555555555555555555555555
40 5555555555555555555555555555555555555555
41 55555555555555555555555555555555555555600
42 555555555555555555555555555555555555556000
39 666666666666666666666666666666666666666
40 6666666666666666666666666666666666666666
41 66666666666666666666666666666666666666700
42 666666666666666666666666666666666666667000
39 777777777777777777777777777777777777777
40 7777777777777777777777777777777777777777

41
42
39
40
41
42
39
40
42
43

77777777777777777777777777777777777777800
777777777777777777777777777777777777778000
888888888888888888888888888888888888888
8888888888888888888888888888888888888888
88888888888888888888888888888888888888900
888888888888888888888888888888888888889000
999999999999999999999999999999999999999
9999999999999999999999999999999999999999
100000000000000000000000000000000000000000
1000000000000000000000000000000000000000000

PL/SQL procedure successfully completed.


Elapsed: 00:00:00.01
--ORACLE CAN NOT HANDLE NUMBERS WITH > 40 DIGITS
--WHEN THE DIGITS ARE ALL 9S, ORACLE IS NOT PRITING THE LENGTH 41.
AND WHEN THE NUMBER OF DIGITS > 40,THE ACTUAL NUMBER IS PRINTED AS 1 FOLLOWED
BY ZEROS

--TO DEBUG MY FUNCTION, I WROTE A CUSTOM PROCEDURE.


set serverout on size 1000000 timing on
SQL> declare
SQL> 2 v_len number;
3 v_tot number;
4 v_num number:=&num;
5 begin
6
7
v_len:=length(v_num);
8
9
10
<<WHILE_LOOP>>
11
v_tot:=0;
12
dbms_output.put_line(v_len);
13
for i in 1..v_len loop
14
dbms_output.put_line(i||' '||substr(v_num,i,1));
15
v_tot:=v_tot+substr(v_num,i,1);
16
end loop;
17
dbms_output.put_line(v_tot);
18
v_num:=v_tot;
19
20
v_len:=length(v_num);
21
if (v_len > 1) then
22
goto WHILE_LOOP;
23
end if;
24
25 dbms_output.put_line(v_tot);
26 end;
27 /
Enter value for num: 53471174487509326626683734665971051554519813719210851244861
07341
old 4: v_num number:=&num;
new 4: v_num number:=534711744875093266266837346659710515545198137192108512448
6107341;
64
1 5
2 3

3 4
4 7
5 1
6 1
7 7
8 4
9 4
10 8
11 7
12 5
13 0
14 9
15 3
16 2
17 6
18 6
19 2
20 6
21 6
22 8
23 3
24 7
25 3
26 4
27 6
28 6
29 5
30 9
31 7
32 1
33 0
34 5
35 1
36 5
37 5
38 4
39 5
40 2
41 0
42 0
43 0
44 0
45 0
46 0
47 0
48 0
49 0
50 0
51 0
52 0
53 0
54 0
55 0
56 0
57 0
58 0
59 0
60 0
61 0
62 0

63 0
64 0
182
3
1 1
2 8
3 2
11
2
1 1
2 1
2
2
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01

--THE ABOVE FUNCTION CAN HANDLE NUMBERS UPTO 40 DIGITS LONG.


ANY NUMBER HAVING > 40 DIGITS, ORACLE IS TAKING "0" AFTER 40TH DIGIT ONWARDS.
TO HANDLE THIS ISSUE, I MODIFIED THE FUNCTION AS FOLLOWES.
--ORACLE CAN ONLY HANDLE NUMBERS UPTO 38 DIGITS LONG + 2 FOR SIGN AND DECIMAL PL
ACE
--MIODIFIED MY PROCEDURE TO ACCEPT THE NUMBER INTO A STRING VARIABLE AND SUM ALL
DIGITS
SQL> set serverout on size 1000000 timing on
declare
SQL> 2 v_len number;
3 v_tot number;
4 v_num varchar2(2000):='&num';
5 begin
6
7
v_len:=length(v_num);
8
9
10
<<WHILE_LOOP>>
11
v_tot:=0;
12
dbms_output.put_line(v_len);
13
for i in 1..v_len loop
14
dbms_output.put_line(i||' '||substr(v_num,i,1));
15
v_tot:=v_tot+to_number(substr(v_num,i,1));
16
end loop;
17
dbms_output.put_line(v_tot);
18
v_num:=v_tot;
19
20
v_len:=length(v_num);
21
if (v_len > 1) then
22
goto WHILE_LOOP;
23
end if;
24
25 dbms_output.put_line(v_tot);
26 end;
/ 27
Enter value for num: 53471174487509326626683734665971051554519813719210851244861

07341
old 4: v_num varchar2(2000):='&num';
new 4: v_num varchar2(2000):='534711744875093266266837346659710515545198137192
1085124486107341';
64
1 5
2 3
3 4
4 7
5 1
6 1
7 7
8 4
9 4
10 8
11 7
12 5
13 0
14 9
15 3
16 2
17 6
18 6
19 2
20 6
21 6
22 8
23 3
24 7
25 3
26 4
27 6
28 6
29 5
30 9
31 7
32 1
33 0
34 5
35 1
36 5
37 5
38 4
39 5
40 1
41 9
42 8
43 1
44 3
45 7
46 1
47 9
48 2
49 1
50 0
51 8
52 5
53 1
54 2
55 4

56 4
57 8
58 6
59 1
60 0
61 7
62 3
63 4
64 1
276
3
1 2
2 7
3 6
15
2
1 1
2 5
6
6
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.02
--MODIFIED MY FUNCTION ACCORDINGLY, TO STORE THE INPUT VALUE IN A STRING VARIABL
E AND PROCESS.
create or replace function num_tot(i_num in varchar2)
return number is
v_len number;
v_tot number;
v_num varchar2(2000):=i_num;
begin
v_len:=length(v_num);
<<WHILE_LOOP>>
v_tot:=0;
for i in 1..v_len loop
v_tot:=v_tot+to_number(substr(v_num,i,1));
end loop;
v_num:=v_tot;
v_len:=length(v_num);
if (v_len > 1) then
goto WHILE_LOOP;
end if;
return v_tot;
end;
SQL>
Enter
07341
old
new

select num_tot('&num') sum_digits_in_number from dual;


value for num: 53471174487509326626683734665971051554519813719210851244861
1: select num_tot('&num') sum_digits_in_number from dual
1: select num_tot('534711744875093266266837346659710515545198137192108512

4486107341') sum_digits_in_number from dual


SUM_DIGITS_IN_NUMBER
-------------------6
SQL> /
Enter value for num: 53471174487509326626683734665971051554519813719210851244861
07343
old 1: select num_tot('&num') sum_digits_in_number from dual
new 1: select num_tot('534711744875093266266837346659710515545198137192108512
4486107343') sum_digits_in_number from dual
SUM_DIGITS_IN_NUMBER
-------------------8
--FOUND THE SUM OF ALL DIGITS OF THE TWO LARGE NUMBERS.
--RAN TESTS USING BOTH FUNCTIONS TO SUM ALL THE DIGITS IN LARGE NUMBERS.
THE FOLLOWING REPORT DISPLAYS THE SUM OF ALL DIGITS IN MY TABLE, WITH THEIR CO
UNTS GROUP BY SUM OF ALL DIGITS OF NUMBERS.
STRANGELY, PERFORMANCE OF THE FUNCTION USING A STRING VARIABLE TO SUM UP ALL T
HE DIGITS IN THE NUMBERS IS BETTER,
COMPARED TO THE PERFORMNACE OF THE FUNCTION USING A NUMBER VARIABLE TO SUM UP
ALL THE DIGITS IN THE NUMBERS.
THIS TEST WAS CONDUCTED ON A 10G DATABASE TABLE CONTAINING 664580 PRIME_NUMBER
S.
SQL> select num_tot(prime_num),count(*) tot_num from prime_num group by num_tot(
prime_num) order by 1;
NUM_TOT(PRIME_NUM)
TOT_NUM
------------------ ---------1
110773
2
110836
3
1
4
110743
5
110760
7
110679
8
110788
7 rows selected.
Elapsed: 00:00:05.63 --HERE THE FUNCTION TAKES A STRING VALUE OF DIGITS AND PROC
ESSES
SQL> select num_tot(prime_num),count(*) tot_num from prime_num group by num_tot(
prime_num) order by 1;
NUM_TOT(PRIME_NUM)
TOT_NUM
------------------ ---------1
110773
2
110836
3
1
4
110743
5
110760

7
8

110679
110788

7 rows selected.
Elapsed: 00:00:06.32 --HERE THE FUNCTION TAKES A NUMERICAL VALUE OF DIGITS AND P
ROCESSES.
HAPPY SCRIPTING

You might also like