Indexing very long number column - oracle

I have a table with few columns including 2 varchar2(200) columns. In this columns we basically store serial numbers which can be numeric or alpha-numeric. Alpha-numeric values always both serials are same in those 2 columns. However for number serials it is a range like (first column value = 511368000004001226 and second column value = 511368000004001425 with 200 different (Qty)). Maximum length of the serial is 20 digits. I have indexed both the columns.
Now I want to sear a serial in-between the above range. (lets say 511368000004001227). I use following query.
SELECT *
FROM Table_Namr d
WHERE d.FROM_SN <= '511368000004001227'
AND d.TO_SN >= '511368000004001227'
Is it a valid query? Can I use <=> operators for numbers in a varchar column?

Yes, You can use >= and <= operators on Varchar2 columns but it will behave like it is string and comparison between strings will take place.
In this case, 4 will be considered greater than 34 means '4' > '34' but number 4 is less than 34.
It is not a good practice to store a number in Varchar2. You will lose the functionality of Numbers if you store them in varchar2.
You can check the above concept using following:
select * from dual where '4' > '34'; -- gives result 'X'
select * from dual where 4 > 34; -- Gives no result
You can try to convert the varchar2 column to number using to_number if possible in your case.
Cheers!!

Your Query is "valid" in the sense, that it works, and will deliver a result. If you are looking from a numeric standpoint, it will not work correctly, as the range operators for VARCHAR columns work the same way, as it would sort an alphanumeric value.
e.g.
d.FROM_SN >= '51000'
AND d.TO_SN <= '52000'
This would match for values, as you would expect, like 51001, 51700, but would also deliver unexpected values like 52, or 5100000000000000
If you want numeric selection, you would need to parse it - which of course only works, if every value in these columns is numeric:
TO_NUMBER(d.FROM_SN) >= 51000
AND TO_NUMBER(d.TO_SN) <= 52000

You may use alphanumerical comparison provided
1) your ranges are of the same length and
2) all the keys in the range are of the same length
Example data
SERNO
----------------------------------------
101
1011
1012
1013
1014
102
103
104
This doesn't work
select * from tab
where serno >= '101' and serno <= '102';
SERNO
----------------------------------------
101
102
1011
1012
1013
1014
But constraining the lentgh of the result provides the right answer
select * from tab
where serno >= '101' and serno <= '102'
and length(serno) = 3;
SERNO
----------------------------------------
101
102

Related

Format mask with leading zero for NUMBER

Which format mask should I use to convert number data from table column NUMBER to char if I want to preserve one leading zero and don't know data "size"? Value could have integral and/or fractional part. All that I know - it's NUMBER.
Source Data (numbers)
.12345678901234567890
100
100.500
12345678901234567890.1234567890
Desired result (text)
0.1234567890123456789
100
100.5
12345678901234567890.123456789
and so on, i.e. number could have unpredictable number of digits in whole part and unpredictable number of digits in fractional part.
A NUMBER data type is a binary value that has no format; if you want to format the number then you will need to convert it to another data-type that can represent the numeric value with a format, such as a VARCHAR2 data-type using the TO_CHAR function:
SELECT value,
RTRIM(
TO_CHAR( value, 'FM999999999999999999999990D99999999999999999999' ),
'.'
) AS formatted_number
FROM table_name
Which, for the sample data:
CREATE TABLE table_name ( value ) AS
SELECT .12345678901234567890 FROM DUAL UNION ALL
SELECT 100 FROM DUAL UNION ALL
SELECT 100.500 FROM DUAL UNION ALL
SELECT 12345678901234567890.1234567890 FROM DUAL
Outputs:
VALUE
FORMATTED_NUMBER
.1234567890123456789
0.1234567890123456789
100
100
100.5
100.5
12345678901234567890.123456789
12345678901234567890.123456789
number could have unpredictable number of digits in whole part and unpredictable number of digits in fractional part.
Just increase the number of 9s before and after the D decimal separator until the number of integer/fractional digits reaches your maximum precision.

Need specific number format in Oracle S9(15)V9(2)

I have a requirement to produce amount fields in zoned decimal format with this specific syntax below.
I don’t know if I need to create a function to handle this or if I can tweak the Oracle number format model. I’m thinking it might require some conditional formatting within a function due to the different requirement for number of digits between positive and negative. I will be performing this formatting on a couple of dozen data elements in the procedure so that might be another reason to use a function. Thoughts?
Requirement:
Amount should be represented by 17 characters (positive number) or 16 characters plus a “}” appended to the end (negative number).
Ex. 0.00 should show as 00000000000000000.
Ex. -935,560.00 should show as 00000000093556000}
Using Oracle 12c.
If I understood you correctly, the input is already formatted and its datatype is VARCHAR2. If that's so, then this might do the job:
SQL> with test (col) as
2 (select '0.00' from dual union all
3 select '25.34' from dual union all
4 select '-935,560.00' from dual
5 )
6 select col,
7 lpad(translate(col, 'x,.-', 'x'),
8 case when substr(col, 1, 1) = '-' then 16
9 else 17
10 end, '0') ||
11 case when substr(col, 1, 1) = '-' then '}'
12 else null
13 end result
14 from test;
COL RESULT
----------- --------------------
0.00 00000000000000000
25.34 00000000000002534
-935,560.00 0000000093556000}
SQL>
What does it do?
lines #1 - 5 - sample data
line #7 - translate removes minus sign, commas and dots
lines #7 - 10 - lpad pads the number (without characters from the previous step) with zeros up to the length of 16 (for negative values) or 17 (for positive values) characters
lines #11 - 13 - if it is a negative value, concatenate } to the end of the result string

Store big number in Oracle -- Please give an example that can store 9e125

The Oracle doc says one can store a number up to 9.99...9 x 10125 with up to 38 significant digits: https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#i16209.
I tried this:
create table bigtest (t number(38,2));
insert into bigtest values (5e40);
But I got
[Error] Execution (8: 29): ORA-01438: value larger than specified precision allowed for this column
It is supposed to be able to store 9.99e125, right? Could any one give an example on how to store 9.99e125?
See DBfiddle here (Oracle 18c).
create table T1 (
anumber number
) ;
insert into t1 ( anumber ) values ( 9.99e125 ) ;
select * from t1 ;
ANUMBER
999000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
One way is to use the number data type without precision and scale specified.
You can specify precision and scale for very large (and also for very small) numbers though. Just keep in mind that negative scale means "that many zeros at the end of an integer" - the total number of digits can be up to precision + absolute value of scale.
In the example below, note that 38 + 84 = 122. The scale must be between -84 and 127, which means that if you do use precision and scale, you can only store numbers < 1e123 - a smaller range than for the full number data type, but still storing very large numbers
create table tbl(x number(38,-84));
insert into tbl values (3.493e121);
select x from tbl;
X
----------
3.4930E+121

Oracle plsql how to check if number has decimal points

Just started working with oracle using toad ide. trying to format the numbers from a table in specific format. the numbers come in from a variable in the table and I want to display the whole numbers as whole numbers and display floats as floats. So far, I can use trim(TO_CHAR (width,'999.999')) to display all numbers with decimal points.
For example: 123.5 will be displayed as 123.500 and 100 will be displayed as 100.000.
What I want to do is display for eg: 100 as 100.
Hope this is clear and I get a solution soon.
I'm using MOD for determining decimals.
select test_value, (case when mod(test_value,1) != 0 then 'DECIMAL' else 'NODECIMAL' END) IS_DECIMAL
from (select 1.5 test_value from dual
union all
select 100 test_value from dual) test_table
If your problem is about the way Toad shows numbers, you can follow the hints in the comments.
If the problem is about the way Oracle shows numbers, converting them to strings, maybe this can help:
SQL> select to_char(1.5, 'TM9') as num from dual union all
2 select to_char(100, 'TM9') from dual;
NUM
----------------------------------------------------------------
1,5
100
You find much more in the documentation
If you need a way to check whether a number has a decimal part or not, you can simply try:
SQL> with numbers(num) as (
2 select 1.5 from dual union all
3 select 100 from dual
4 )
5 select case
6 when floor(num) = num
7 then to_char(num, 'FM999999') || ' has not a decimal part'
8 else
9 to_char(num, 'FM9999D000') || ' has a decimal part'
10 end as checkString
11 from numbers;
CHECKSTRING
------------------------------
1,500 has a decimal part
100 has not a decimal part

Oracle cursor removes leading zero

I have a cursor which selects date from column with NUMBER type containg floating point numbers. Numbers like 4,3433 are returned properly while numbers smaller then 1 have removed leading zero.
For example number 0,4513 is returned as ,4513.
When I execute select used in the cursor on the database, numbers are formatted properly, with leading zeros.
This is how I loop over the recors returned by the cursor:
FOR c_data IN cursor_name(p_date) LOOP
...
END LOOP;
Any ideas why it works that way?
Thank you in advance.
You're confusing number format and number value.
The two strings 0.123 and .123, when read as a number, are mathematically equals. They represent the same number. In Oracle the true number representation is never displayed directly, we always convert a number to a character to display it, either implicitly or explicitly with a function.
You assume that a number between 0 and 1 should be represented with a leading 0, but this is not true by default, it depends on how you ask this number to be displayed. If you don't want unexpected outcome, you have to be explicit when displaying numbers/dates, for example:
to_char(your_number, '9990.99');
It's the default number formatting that Oracle provides.
If you want to specify something custom, you shall use TO_CHAR function (either in SQL query or PL/SQL code inside the loop).
Here is how it works:
SQL>
SQL> WITH aa AS (
2 select 1.3232 NUM from dual UNION ALL
3 select 1.3232 NUM from dual UNION ALL
4 select 332.323 NUM from dual UNION ALL
5 select 0.3232 NUM from dual
6 )
7 select NUM, to_char(NUM, 'FM999990D9999999') FORMATTED from aa
8 /
NUM FORMATTED
---------- ---------------
1.3232 1.3232
1.3232 1.3232
332.323 332.323
.3232 0.3232
SQL>
In this example, 'FM' - suppresses extra blanks, '0' indicates number digit including leading/trailing zeros, and '9' indicates digit suppressing leading/trailing zeros.
You can find many examples here:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34570

Resources