Oracle Number data type and its strictness - oracle

I'm very new to oracle but I've been learning about it in class and I've recently come across the number data type. I've read the documentation regarding scale and precision (s,p) but I still am not positive regarding the type's proper usage.
Let's say I want to store percent values as a decimal. The decimal can be anywhere from 0 to 1 and may have up to 3 numbers following the decimal place.
Some possible decimals to be stored may include:
.66
.553
1.00
If I were to make the column NUMBER(4,3) would that work EVEN IF there were only two numbers? See below
.22
.10
.35
etc...
In short, does the number type require that the EXACT sizes are met? Eg. Would NUMBER(4,3) ABSOLUTELY REQUIRE that the data inserted is 4 numbers, 3 of them falling after the decimal place?
Thanks for the help!

Data types for columns limit the range of values that can be stored. But they don't do anything to force a particular length or precision.
Just like you can store a single character or a NULL in a VARCHAR2(100) column, you can store numbers with less than 3 digits of precision and less than 4 digits of scale. For example, the values 0 and 6.1 are both perfectly valid for a NUMBER(4,3) column. If you insert a value that has too many digits of precision, the value will be silently rounded to the precision specified in the column definition.
SQL> create table foo (
2 col1 number(4,3)
3 );
Table created.
SQL> insert into foo values( 9.999 );
1 row created.
SQL> insert into foo values (0);
1 row created.
SQL> insert into foo values( 6.1 );
1 row created.
SQL> insert into foo values( 1.2345 );
1 row created.
SQL> select * from foo;
COL1
----------
9.999
0
6.1
1.235

Related

How does Number data type work in Oracle 21c?

I created a table like this:
CREATE TABLE table(
id INTEGER GENERATED ALWAYS AS IDENTITY,
nome VARCHAR2(100 CHAR)
)
ALTER TABLE table ADD CONSTRAINT table_pk PRIMARY KEY (ID);
CREATE UNIQUE INDEX TABLE_UNIQ_IDX ON TABLE(NOME ASC);
ALTER TABLE table ADD (PERC NUMBER(1, 2) NOT NULL);
Then I tried to write 2 records on it:
INSERT INTO TABLE(NOME,PERC)VALUES('a',0.8);
INSERT INTO TABLE(NOME,PERC)VALUES('b',0.2);
Then I received this error:
ORA-01438: valor maior que a precisão especificada usado para esta coluna
Translated:
ORA-01438: value larger than specified precision allows for this column
I tried select cast (0.8 as number(1,1)) from dual; and it worked but when I tried select cast (0.8 as number(1,2)) from dual; I received the same error.
I then tried select cast (0.81 as number(1,2)) from dual; and received the same ORA-01438.
I changed my field to number(1,1), no big deal, but how does this "Number" data type work?
Shouldn't select cast (0.81 as number(1,2)) from dual; have worked?
Why does select cast (0.81 as number(2,2)) from dual; work and
select cast (0.81 as number(2,3)) from dual; does not?
Thanks for any help
If you have NUMBER(precision, scale) then precision is the number of digits and scale is the number of decimal places.
So, NUMBER(1, 2) has a single digit and 2 decimal places. The minimum value it can store is -0.09 and the maximum it can store is +0.09.
NUMBER(2,2) works as it stores 2 digits in 2 decimal places (from -0.99 to +0.99).
NUMBER(2,3) does not work as it stores 2 digits in 3 decimal places (from -0.099 to +0.099).
What you said, is that perc column should accept numeric values whose length is 1, and out of that 1, you want to keep 2 decimal places. That won't work.
SQL> create table test (perc number(1, 2));
Table created.
SQL> insert into test values (0.8);
insert into test values (0.8)
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
Perhaps you meant to put it vice versa?
SQL> alter table test modify perc number(2, 1);
Table altered.
SQL> insert into test values (0.8);
1 row created.
SQL>

when we declared number datatype in oracle what it will take default data type?

I was declared one column in oracle datatype is number ex:cust_acc_no NUMBER (9) DEFAULT (0),.
After creating table that column take double datatype why?
but that column is account number so when i select that particular field it shows account numbers with decimal.
If you didn't put any decimal numbers into it, then they aren't decimal numbers. If you think they are, please, post an example - copy/paste your SQL*Plus session which shows what you're saying. I suspect that it is matter of formatting, not data storage.
By the way, you could have used the INT datatype, e.g.
SQL> create table test (cust_acc_no int default 0);
Table created.
SQL> insert into test
2 select 100 from dual union
3 select 0.5 from dual union
4 select 20.6 from dual;
3 rows created.
SQL> select * from test;
CUST_ACC_NO
-----------
1
21
100
SQL>

oracle value 99999999 getting rounded

I created the below table:
create table ex_employee (id number(20,4));
Then I have insert the below values:
insert into ex_employee values (9999999999999999.9999);
commit;
The result is being rounded up;
10000000000000000.0000
In this link they explained if the precision execeeded then it will round up.
what should I do to keep the value not get rounded:
9999999999999999.9999
The result is being rounded up [to] 10000000000000000.0000
what should I do to keep the value not get rounded: 9999999999999999.9999
As you noticed yourself, this is a display problem, as your NUMBER(20,4) has sufficient significant digits to precisely represent that base10 number.
If addition to Lalit's answer concerning "display format", a common source for that behavior is to use an IEEE 754 float/double values at application-level to read back those numbers (resp. 7 / 15 significant decimal digits only). In addition, all decimal digits cannot be accurately represented using binary representation.
If your host language has support for that, you should "long decimal numbers". For example, Java has BigDecimal. Python has Decimal.
Just set the numformat properly. In SQL*Plus, you could do it as set numformat.
SQL> set numformat 9999999999999999.9999
SQL> create table ex_employee (id number(20,4));
Table created.
SQL> insert into ex_employee values (9999999999999999.9999);
1 row created.
SQL> select id from ex_employee;
ID
----------------------
9999999999999999.9999
SQL>

Oracle Precision

I want a number to take values between -7.2E-75 to +7.2E+75. How should I specify precision and scale for the NUMBER. (The scale range is 1 to 38 and precision is -84 to 127).
If there is any other way to accomplish this please suggest.
The numeric values you propose are well within the limits of the Oracle NUMBER datatype.
Do you need to specify a precision? Defining a column as just NUMBER is allowed:
SQL> desc t1
Name Null? Type
----------------------------------------- -------- ----------------------------
COL1 NUMBER
COL2 NUMBER
COL3 NUMBER
COL4 NUMBER
SQL> insert into t1 (col1, col2) values ( -7.2E-75, +7.2E+75);
1 row created.
SQL>
If it's the range bounds which are bothering you, you need to define a CHECK constraint to enforce the rule.
"Suppose i want COL1 to take 123456766675544.344546567676, with NUMBER as datatype its failing"
Failing? How? That value works fine for me (same table as before):
SQL> insert into t1 (col1) values ( 123456766675544.344546567676);
1 row created.
SQL>
So, please provide more details, such as the error message.
"When i fire the above query it is showing just 123456766675544,"
That sounds like a display issue. The right values are being inserted. Check this out:
SQL> set numwidth 50
SQL> select col1 from t1
/
2
COL1
--------------------------------------------------
7.20000000000000000000000000000000000000000000E+75
123456766675544.344546567676
SQL>
In this case, setting the NUMWIDTH to its maximum allowed value ( in SQL*plus) allows us to display one value but the other is still too big, and so we have to use scientific notation.

OCI: Determine length of text representation of query columns

My goal is to execute a query (SELECT), fetch results and output them as text. Query is given as a parameter and can be e.g. select * from t.
I use OCIStmtPrepare and OCIStmtExecute, then I can describe columns of the query by OCIParamGet and series of OCIAttrGet. Suppose I get OCI_ATTR_DATA_TYPE = 12 (DATE) for one of the columns. Then OCI_ATTR_DATA_SIZE = 7 -- this is size of internal DATE representation.
I want to get this DATE as text, with respect to currect NLS settings. For that I use OCIDefineByPos with dty = SQLT_STR. It works alright, but I also need to supply a buffer for fetching. The question is: what size of buffer do I need?
Evidently it depends on NLS_DATE_FORMAT. I believe that Oracle knows this value:
SQL> create table x as select to_char(sysdate) d from dual;
Table created.
SQL> select value from nls_session_parameters where parameter='NLS_DATE_FORMAT';
VALUE
----------------------------------------
DD.MM.RR
SQL> select data_length from dba_tab_columns where table_name='X';
DATA_LENGTH
-----------
8
This is the exact length. Only when date format is masked from Oracle (by a function, for example), it uses absolute maximum (?) value of 75:
SQL> create or replace function get_date_format return varchar2 is
2 begin
3 return 'DD.MM.RR';
4 end;
5 /
Function created.
SQL> create table x as select to_char(sysdate,get_date_format) d from dual;
Table created.
SQL> select data_length from dba_tab_columns where table_name='X';
DATA_LENGTH
-----------
75
All said above applies to NUMBER as well.
So, is it possible to get length of text representation of a column in OCI?
The maximum buffer size for any date is 75. The maximum buffer size for any number is 42.
I hope that helps.
You can determine needed buffer size by calling OCIAttrGet for OCI_ATTR_DISP_SIZE attribute. It returns 40 for NUMBER, 75 for DATE, N for VARCHAR2(N). Add 1 byte for Null-termination and you good to go.
Yes - the trick is that in C, a string is really a pointer to a character array, so you would say char* mystring = OCIStringPtr(envhp, x); where x is a pointer to an OCIString, which you can get back by connecting with OCI_OBJECT set and asking for a SQLT_VST instead of an SQLT_STR. The actual memory for the string is allocated for you in the global env by OCI behind the scenes.

Resources