Resulting precision of operations on Oracle NUMBER - oracle

What is the precision of the value resulting in an operator on 2 Oracle default/as-given NUMBER columns (where NUMBER has no (p,s) set))? Like if I:
create table foo(field1 NUMBER, field2 NUMBER);
insert into foo (field1, field2) values (1.1, 3);
select field1/field2 as f1df2 from foo;
Will f1df2 be 0.3666666666666...7?

Will f1df2 be 0.3666666666666...7?
Yes.
Numbers inserted into NUMBER columns that were created without setting p,s are stored 'as given'. The resulting precision of an operation on these columns appear to be the precision and scale of highest precision and scale column:
create table test_number(f1 number, f2 number, f3 integer);
-- remember integer in Oracle is NUMBER(38)
insert into test_number (f1, f2, f3) values (1.1, 3, 4);
select f1/f2 as f1df2, f2/f3 as f2df3 from test_number
Results in:
F1DF2 |F2DF3
------------------------------------------|-----
0.3666666666666666666666666666666666666667|0.75
Note that this is true even if f1 was re-defined to be NUMBER(p, 1)! It appears that defining (p,s) for a NUMBER field only restricts precision of the data being entered into the field.
Now, what happens if we mixed the arbitrary precision type with a float? Well, according to Oracle Numeric Precedence rules:
If any of the operands is BINARY_DOUBLE, then Oracle attempts to convert all the operands implicitly to BINARY_DOUBLE before performing the operation.
If none of the operands is BINARY_DOUBLE but any of the operands is BINARY_FLOAT, then Oracle attempts to convert all the operands implicitly to BINARY_FLOAT before performing the operation.
Otherwise, Oracle attempts to convert all the operands to NUMBER before performing the operation

Related

I want to export data from oracle database to csv, and I am putting a number filter on a varchar column. It thows ORA:01722 error. Please suggest

Select count(*) from table where loc between 300 to 400.
loc is a varchar column.
it is not selecting all the data
checking the count, gives ORA :01722 error
exporting the results with error.
Edit from comment:
loc contains values less than 300, more than 400, and alphanumeric like 'GT' , '3KT1'
loc is a varchar column.
[From comment] The Loc column has char type value also like GJ, 3KT1
LOC contains values which are not convertible to numbers. This matters because your WHERE clause predicates are defined as numbers, so Oracle applies an implicit to_number(loc) to the query. This is why using proper data types is best practice: it doesn't help you now but please learn the lesson, and use NUMBER columns for numeric data.
In the meantime you have several options to deal with your shonky data model.
If you're lucky enough to be using Oracle 12c R2 you can use the new VALIDATE_CONVERSION() function to exclude values of loc which can't be cast to numbers. Find out more
If you're using an earlier version of Oracle you can build your own function:
create or replace function is_number
(p_str in varchar2) return number
is
n number;
rv number;
begin
begin
n := to_number(p_str);
rv := 1;
exception
when invalid_number then
rv := 0;
end;
return rv;
end;
The weakest option would be casting the predicates to strings. where loc between '300' to '400' would include '3000', '4' and various other values you probably don't want.
Here is a LiveSQL demo (free Oracle Technet account required, alas).
Your current query is trying to compare a varchar to a number. So it tries to convert the varchar to a number on the fly. This is called implicit conversion.
You should make it compare a varchar to a varchar.
Use single quotes so that you are comparing to varchars, not numbers
Select count(*) from table where loc between '300' to '400'
Then go and read about implicit conversion
Based on the update to your question, this column is a legitimate varchar and should not be converted to a numeric data type.
However you do need to work out whether you are incorrectly storing different types of data in the same column

SQLDeveloper query automatic padding CHAR field

Given the table ATABLE with a field AFIELD of type CHAR(8), and where i have a field with value "1234567 "
Why, in SQL Developer, if I query:
SELECT * FROM ATABLE WHERE AFIELD = '1234567';
It will automatically pad the missing space and return the results, and if I query with :
SELECT * FROM ATABLE WHERE AFIELD = :value;
and input the value, it wont ?
From the documentation:
Within expressions and conditions, Oracle treats text literals as though they have the data type CHAR by comparing them using blank-padded comparison semantics.
When you do WHERE AFIELD = '1234567' the text literal '1234567' is treated as char and blank-padded comparison semantics are used to compare the column value and the literal. Even though the literal doesn't have the trailing space, those semantics see them as the same, so it finds a match.
When you use a bind variable the literal you assign to it is a char, but the bind variable itself is varchar2 - even if you declare it as char, oddly, though in that case the value is blank-padded anyway:
var char_value char(8);
exec :char_value := '1234567';
var varchar2_value varchar2(8);
exec :varchar2_value := '1234567';
select dump('1234567') as d1, dump(:char_value) as d2, dump(:varchar2_value) as d3
from dual;
D1 D2 D3
------------------------------------ ------------------------------------ ------------------------------------
Typ=96 Len=7: 49,50,51,52,53,54,55 Typ=1 Len=8: 49,50,51,52,53,54,55,32 Typ=1 Len=7: 49,50,51,52,53,54,55
The text literal is data type 96 (char), while both bind variables are type 1 (varchar/varchar2); but notice the char_value bind variable has the trailing space, with length 8 and the last character as code point 32.
When you compare your char column value with a varchar2 bind variable the column value is implicitly converted from char to varchar2:
The following rules govern implicit data type conversions:
During SELECT FROM operations, Oracle converts the data from the column to the type of the target variable.
So your space-padded char(8) column value is implicitly converted to varchar2(8) to match the bind variable's data type, and then because they are varchar2 the nonpadded comparison semantics are used.
When you compare your char(8) column with the supposedly-char(8) bind variable, you're actually comparing with a padded varchar2(8) - but both the implicitly converted column value and the blank-padded bind variable are actually the same, both with the trailing space; '1234567 ' is the same as '1234567 ', so there is a match, even with nonpadded comparison semantics.
With the varchar2(8) bind variable the same thing happens, but now the bound value is not padded, and as you are using nonpadded comparison semantics to compare '1234567 ' with '1234567' - they are not the same, so there is no match, and no data is returned by the query.
As #a_horse_with_no_name said you should almost always use varchar2 rather than char. But if you must use it and are stuck with it then at least make sure you use the same data type for comparisons.
You are right
SELECT * FROM ATABLE WHERE AFIELD = :value;
does not work with CHAR as you desire.
Anyway I have noticed that the following query works as you desire:
SELECT * FROM ATABLE WHERE AFIELD = &value;
If you use &value in several places, you can use &&value (double &) the first time (and &value elsewhere),
in order to avoid to input the same value several times;
when you have to change that value, you can undefine it with:
undef value;

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>

Number becomes to BigDecimal after the hibernate reverse engeering?

I set the field as Number like below in the oracle database.
name type length scale
EMP_GENDER NUMBER 0 0
After the hibernate reverse engineering,this filed's type becomes to BigDecimal.
private BigDecimal empGender;
But when I set the length to 2 in database,it could be right and field type in the entity become to Integer.
How did this happen?
When Hibernate reverse engineers your schema, that will use Oracle's Mete-data tables to extract table and columns information.
One of the them will be user_tab_columns View.
Having
create table EMP (EMP_GENDER number);
To extract EMP table,s column information you may use:
select *
from user_tab_columns
where user_tab_columns.TABLE_NAME = 'EMP'
The query result will be characterization of every column of EMP table.
We will see DATA_TYPE , DATA_LENGTH and DATA_PRECISION columns.(using Oracle 10 g)
Having:
create table EMP (EMP_GENDER number(2));
We will see
When not defining precision for numeric type, the DATA_LENGTH (default is 22 ) will be treated as precision.
So a number with length of 22 will be translated to Big-decimal by Hibernate(that will exceed the maximum precision of decimal data type)
When numeric type precision is equals to 2, the Integer data type will be sufficient.
You must specify the exact numeric precision on table creation to prevent the problem.

Oracle Number data type and its strictness

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

Resources