How to prevent rounding in Oracle database? - sql

I want to prevent a number from rounding in Oracle Database
I want to prevent a number from rounding in Oracle Database
I want to prevent a number from rounding in Oracle Database
I want to prevent a number from rounding in Oracle Database
price = 14.089 => becomes : 14.09
In my data base the type of the Column is DECIMAL
I want to get the 3 numbers of the price after the comma.
can anyone hel me how to fix this problem
SELECT
*
FROM
user_tab_columns
WHERE
table_name = 'GEST_SANTE.PRESTATION_PHARMACIE'
AND column_name = 'PRICE';
The result after executing the query:
INSERT INTO ""."" (
"OWNER",
"TABLE_NAME",
"COLUMN_NAME",
"DATA_TYPE",
"DATA_TYPE_MOD",
"DATA_TYPE_OWNER",
"DATA_LENGTH",
"DATA_PRECISION",
"DATA_SCALE",
"NULLABLE",
"COLUMN_ID",
"DEFAULT_LENGTH",
"DATA_DEFAULT",
"NUM_DISTINCT",
"LOW_VALUE",
"HIGH_VALUE",
"DENSITY",
"NUM_NULLS",
"NUM_BUCKETS",
"LAST_ANALYZED",
"SAMPLE_SIZE",
"CHARACTER_SET_NAME",
"CHAR_COL_DECL_LENGTH",
"GLOBAL_STATS",
"USER_STATS",
"AVG_COL_LEN",
"CHAR_LENGTH",
"CHAR_USED",
"V80_FMT_IMAGE",
"DATA_UPGRADED",
"HISTOGRAM"
)
VALUES
(
'GEST_SANTE',
'PRESTATION_PHARMACIE',
'PRICE',
'NUMBER',
NULL,
NULL,
'22',
NULL,
'3',
'Y',
'23',
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
'NO',
'NO',
NULL,
'0',
NULL,
'NO',
'YES',
'NONE'
);

You have two issues and are conflating the two.
Issue 1: Data Storage
You are storing the data in a column with the DECIMAL(*,3) data type. This can store, at most, 3 decimal places. It is IMPOSSIBLE to store data with more than 3 decimal places and if you attempt it then Oracle will round the input to 3 decimal places because you defined the column as only having 3 decimal places and Oracle is doing exactly what you told it to do.
For example:
CREATE TABLE your_table_name (
price DECIMAL(*,3)
);
Then:
INSERT INTO your_table_name (price) VALUES (14.0895);
It is IMPOSSIBLE to store the exact value as the column is only defined to store 3 decimal places so Oracle will round the number to 14.090 and store that value. Since 14.090 and 14.09 are identical values the database only needs to store 14.09 and the third decimal place is irrelevant as it is 0 and does not need to be stored (and the value is unaffected).
Yes, rounding has occurred but it is because YOU defined the column to only store 3 decimal places and tried to insert a number with 4 decimal places so Oracle does its best to store the closest value it can (given the constraints that YOU set on the table) and that is through rounding to the appropriate scale.
If you want to change the scale of a column so that you can store a greater number of decimal places then you can do that using:
ALTER TABLE your_table_name MODIFY (price DECIMAL(*,5));
However, it will not change the data already stored in the column; but it would allow you to insert more precise values at a later date.
fiddle
Issue 2: Displaying Data
Oracle does NOT store data with any particular formatting. If you want to display a value in the database as a number then Oracle will only display the stored digits; it will not automatically format the number to the maximum scale of the column.
For example:
SELECT price FROM your_table_name;
Will output:
PRICE
14.09
If you want to display it with any particular formatting then YOU need to convert the number to a formatted string in the SELECT statement and provide the format model to use in the formatting. So to always display 3 decimal places:
SELECT TO_CHAR(price, 'fm999990.000') AS price
FROM your_table_name;
Will output:
PRICE
14.090
fiddle

You can use this :
FLOOR(price * 1000)/1000;

Related

ORA-12899 value too large for column despite of same length

I am running the following query. But getting ORA-12899. Altough the length of string am trying to insert is 30.
INSERT INTO TABLE1 SELECT * FROM temp_Table1 where LENGTH(column1)=30;
SQL Error: ORA-12899:value too large for column "TABLE1"."column1" (actual: 31, maximum: 30)
select column1 from temp_Table1 where LENGTH(column1)=30;
Testing  - HLC/TC Design Corre
Desc temp_Table1
column1 VARCHAR2(30)
Desc Table1
column1 VARCHAR2(30)
You're seeing the difference between character and byte length semantics:
You must specify a maximum length for a VARCHAR2 column. This maximum must be at least 1 byte, although the actual string stored is permitted to be a zero-length string (''). You can use the CHAR qualifier, for example VARCHAR2(10 CHAR), to give the maximum length in characters instead of bytes. A character is technically a code point of the database character set. You can use the BYTE qualifier, for example VARCHAR2(10 BYTE), to explicitly give the maximum length in bytes. If no explicit qualifier is included in a column or attribute definition when a database object with this column or attribute is created, then the length semantics are determined by the value of the NLS_LENGTH_SEMANTICS parameter of the session creating the object.
If your session is using byte semantics then the column in your table will default to that:
select value from nls_session_parameters where parameter = 'NLS_LENGTH_SEMANTICS';
VALUE
----------------------------------------
BYTE
create table t42(text varchar2(5));
Table T42 created.
select char_used from user_tab_columns where table_name = 'T42' and column_name = 'TEXT';
C
-
B
That is the same as explicitly doing:
create table t42(text varchar2(5 byte));
If your source data is five characters but includes any multibyte characters then the number of bytes will exceed five:
insert into t42 (text) values ('Hello');
1 row inserted.
insert into t42 (text) values ('Señor');
SQL Error: ORA-12899: value too large for column "SCHEMA"."T42"."TEXT" (actual: 6, maximum: 5)
Which is what you're seeing. When you insert the values from your other table you are filter on the length of the values, but length() counts characters rather than bytes. There is a lengthb() function that does count bytes. If you check the byte length of the 30-character value you're selecting you'll see it is in fact 31 bytes, so one of those characters is multibyte.
with t42 (text) as (
select 'Hello' from dual
union all select 'Señor' from dual
union all select 'Testing  - HLC/TC Design Corre' from dual
)
select text, length(text) as chars, lengthb(text) as bytes, dump(text, 16) as hex
from t42;
TEXT CHARS BYTES HEX
------------------------------- ----- ----- ----------------------------------------------------------------------------------------------------------
Hello 5 5 Typ=1 Len=5: 48,65,6c,6c,6f
Señor 5 6 Typ=1 Len=6: 53,65,c3,b1,6f,72
Testing  - HLC/TC Design Corre 30 31 Typ=1 Len=31: 54,65,73,74,69,6e,67,c2,a0,20,2d,20,48,4c,43,2f,54,43,20,44,65,73,69,67,6e,20,43,6f,72,72,65
From the dump() values you can see that after Testing (54,65,73,74,69,6e,67) and before the space and dash (20,2d) you have c2,a0, which is the UTF-8 multibyte non-breaking space character. (You often see that, along with curly quotes and other non-ASCII-range characters, in text that has been copied from,. say, a Word document).
You can either change your insert to filter on LENGTHB(column1)=30 (which will exclude the row you currently find), or change your column definition to 30 characters instead of 30 bytes:
drop table t42;
Table T42 dropped.
create table t42(text varchar2(5 char));
Table T42 created.
select char_used from user_tab_columns where table_name = 'T42' and column_name = 'TEXT';
C
-
C
insert into t42 (text) values ('Hello');
1 row inserted.
insert into t42 (text) values ('Señor');
1 row inserted.
Or replace any unexpected multibyte characters with single-byte equivalents, if that's possible and makes sense for your data; in this case a normal space might work, but with any substitution you are destroying information that might actually be important.
Try to change your table like
ALTER TABLE1 MODIFY column1 VARCHAR2(30 CHAR)
The error states that your column1 can store maximum of 30 characters and you are passing more than 30 characters in it which results in the error.
You can also refer this article: Oracle Database - Bytes or Characters for VARCHAR2 and CHAR
ORA-12899
Often times, as our companies grow and evolve in response to an
expansion in the form of client-base, staff, profit or markets, the
data associated with this growth will also change. Data systems like
Oracle have the innate ability to remain fairly flexible in regards to
working with this variance in information. Still, even the most
versatile database systems require maintenance and refining in the
face of increased data traffic. This work is essential to
accommodating any constraints on memory or necessary redefinitions of
parameters. The ORA-12899 error is representative of an instance in
which either an uptick in data or a user error is forcing Oracle to
stall during its requested action.
THE PROBLEM
The ORA-12899 is an Oracle error that occurs when the value entered
into the column string is too large. What this means is that an
attempt was made by the user to update or insert a column with a value
that is too wide for the destination column. The name of a particular
column will be given and the actual width of the value, as well as the
maximum width permitted for the column, will be associated with that.
As mentioned, the value can be given in the form of characters. In the
event that the width is reported in characters, this will mean that
character length semantics are operating for the column. Otherwise the
width will be reported in bytes. Essentially, this error results from
trying to push through a value, or set of values, that exceed the
specified maximum width of the column. So, how does a user correct
this type of error?
THE SOLUTION
To begin, open up the OERR utility. The user will require the full
ORA-12899 message to receive the proper feedback on the error. This
will provide more information on the error and allow further
investigation. Typically, the error can come from one of three
sources. The first source is the SQL statements that have been
generated. Checking source and destination column data types to
discover whether they are compatible with current formats is the
second source. Lastly, the user can look at the destination column
width – where the value is being assigned – to make sure it is large
enough to accommodate the maximum value that the user anticipates
assigning. Let us now turn to an example that corrects ORA-12899.
Suppose the user has created the following table:
CREATE TABLE Clients(
ClientID varchar2(9) PRIMARY KEY,
Client_Contact varchar2(40) NOT NULL,
Address varchar(20) NOT NULL,
Zip varchar2(5) NOT NULL,
Client_Number varchar2(11) NOT NULL)
The user then attempts to issue an INSERT VALUES statement that looks
something like this:
INSERT INTO Clients VALUES(
727546345,
‘Roger Holcomb’,
‘—Benjamin Road Syracuse’,
‘-----‘, 05307623754)
The user might try to run the statement from here, but will receive
the following error message:
Error starting at line 7 in command: INSERT INTO Clients
VALUES(727546345, ‘Ricky Galorey’, ‘18 Benjamin Road Syracuse’,
‘13208’, 05307623754) Error report: SQL Error: ORA-12899: value too
large for column “ORGANIZATIONS”. “MARKET”. “ADDRESS”(actual: 25,
maximum: 20) 12899. 00000 – “value too large for column %s (actual:
%s, maximum: %s)”
This error statement indicates that the variable ‘Address’ cannot hold
more than twenty characters as that would exceed the width of the
column parameter. When we look back at the address value (’18 Benjamin
Road Syracuse’) we can see that the total number of characters (25)
exceeds the maximum number allowed for the width of the column. To
correct this, the user can change the VARCHAR2 for address to an
amount that can accommodate the typical address length that their
company would input.
The above answer original URL
Due to different NLS settings in the target table database it might require more bytes in the target.
Try altering the table as
alter Table1 modify column1 varchar2(30 char)

Avoid inserting exponential value in DB Float column

I have a table like
CONTACT
Name Null Type
------------------------------ -------- -----------
CONTACT_ID NOT NULL NUMBER
NAME NOT NULL VARCHAR2(45)
EMAIL NOT NULL VARCHAR2(45)
ADDRESS NOT NULL VARCHAR2(45)
TELEPHONE NOT NULL VARCHAR2(45)
AMOUNT NOT NULL FLOAT(126)
and the insert statement is:
Insert into contact("CONTACT_ID","NAME","EMAIL","ADDRESS","TELEPHONE","AMOUNT")
values ('36','babusailesh1117777','hainatu1#gmail.com','Vietnam1',
'0904277091','0.0000000555559080767');
When I see the final value inserted in the database, I see an exponential value.
How can I avoid this at database level for all tables?
It isn't stored as an exponential, it's stored in Oracle's internal number representation. When you query it, it's displayed with your sessions's current number format:
select 0.0000000555559080767 from dual;
0.0000000555559080767
---------------------------------------
5.6E-08
Which you can override in SQL*Plus or SQL Developer:
set numformat 999.9999999999999999999
select 0.0000000555559080767 from dual;
0.0000000555559080767
------------------------
.0000000555559080767
Or explicitly format the value as a string, for display only:
set numf ""
select to_char(0.0000000555559080767, '9990.9999999999999999999') from dual;
TO_CHAR(0.000000055555908
-------------------------
0.0000000555559080767
If you have a client application retrieving and using the value then it should query it as a float, into a suitable data type for the client's language, and then it's up to the client how it's displayed.
You also shouldn't be inserting a string into the float column, that just does an implicit conversion; the last argument in your insert should be 0.0000000555559080767 rather than the quoted '0.0000000555559080767'.
This is a function of the way the value is displayed, not what is being stored in the database. The database just stores a numeric float value, and whatever retrieves and displays the data decides how to display that. The exponential value you mention is common for displaying such floating point numbers.
You can have Oracle return a string formatted in a way for display using a function such as to_char, that allows you to set formatting. However, it may make more sense to handle this in whatever program or code is using the database.
Also note that floating point numbers have limited precision, so if you need to get that exact number string back, a float is not the way to go.

SQL Datatype to use when inserting money

I am using Oracle SQL database and I have to insert a monetary value(salary) as part of a row. For some strange reason the money command isnt working, is there any alternates that would work with this?
Data input format: £00,000.000
CREATE TABLE staff
(staffno CHAR(6) NOT NULL
, staffsurname VARCHAR(8) NOT NULL
, staffforename VARCHAR(7) NOT NULL
, salary MONEY NOT NULL
, PRIMARY KEY (staffno)
);
Look at this line
salary MONEY NOT NULL
There is no existing money datatype.
If you are looking for something similar to SQL-Server small money type, you want to use a Number(10,4) and then format the number.
You can format the number using to_char function
select to_char(yourColumn, '$99,999.99') from yourTable where someCondition
The "strange" reason is simple: There is no MONEY data type.
The data type most appropriate for monetary values would be NUMBER (using an appropriate scale). Since it is a decimal floating-point type, it is better suited for monetary values than the binary floating-point types BINARY_FLOAT and BINARY_DOUBLE.
Note, though, that you will still need to parse the input string £00,000.000 in your front end and send it as a numeric value to the back end.

H2 DB CSVREAD command converting value to date before placing into VARCHAR

I am attempting to load a tab delimited text file which contains a column of values which happen to look exactly like a date, but aren't. It appears that the CSVREAD command scans the row, converts the text value in the column to a java.Sql.Date, and then sees that the target column is a VARCHAR and executes toString() to obtain the value...which is exactly NOT what I need. I actually need the raw unconverted text with no date processing whatsoever.
So, is there some way to turn off "helpful date-like column conversion" in the CSVREAD command?
Here's the simplest case I can make to demonstrate the undesired behavior:
CREATE TABLE x
(
name VARCHAR NOT NULL
value VARCHAR
) AS
SELECT * CSVREAD('C:\myfile.tab', null, 'UTF-8', chr(9))
;
The file contains three rows, a header and two records of values:
name\tvalue\n
x\t110313\n
y\t102911\n
Any assistance on how I can bypass the overhelpful part of CVSREAD would be greatly appreciated. Thank you.
(It seems you found this out yourself, but anyway):
For CSVREAD, all columns are strings. The CSVREAD function or the database do not try to convert values to a date, or in any other way try to detect the data type. The database only does what you ask it for, which is read the data as a string in your case.
If you do want to convert a column to a date, you need to do that explicitly, for example:
CREATE TABLE x(name VARCHAR NOT NULL, value TIMESTAMP) AS
SELECT *
FROM CSVREAD('C:\myfile.tab', null, 'UTF-8', chr(9));
If non-default parsing is needed, you could use:
CREATE TABLE x(name VARCHAR NOT NULL, value TIMESTAMP) AS
SELECT "name", parsedatetime("value", "M/d/y") as v
FROM CSVREAD('C:\myfile.tab', null, 'UTF-8', chr(9));
For people who don't have headers in there csv files the example could be like this:
CREATE TABLE x(name VARCHAR NOT NULL, value TIMESTAMP) AS
SELECT "0", parsedatetime("1", 'd-M-yyyy') as v
FROM CSVREAD('C:\myfile.tab', '0|1', 'UTF-8', '|');
Beware of the single quotes around the date format. When I tried the example from Thomas it gave me an error using H2:
Column "d-M-yyyy" not found; SQL statement:
My csv files:
firstdate|13-11-2013\n
seconddate|14-11-2013

SQL Server Inserting Decimal, but selecting Int

I have a table with two decimal(18,0) fields.
I am inserting into this table, two decimal values. For example, 1.11
When I select from the table (with no casts), I get 1.
I'm losing all percision and I have no clue why.
insert into TEST values (153, 'test', 'test', 1, 1, 1.11, 1.11)
Select * from TEST and they are 1 and 1 instead of 1.11,1.11
Any Ideas?
When you declare a field as decimal(18,0), you are saying that you want 0 digits of precision after the decimal point. You're going to want to define those columns as decimal(18,2) (or however many digits of precision you desire) in order to maintain a value of 1.11.
Refer to the MSDN page on decimal and numeric types for the grisly details.
Define the Precision to Decimal every time else it stores only int values not Decimal values
Try changing to type decimal(9,2)
Maybe try creating the columns as
decimal(18,2)