Convert Integer Into Number(p,s) During Insert - oracle

I have a Table in Oracle like:
create table TEST (num number(7,2))
And i want to insert a integer into that table like that:
insert into TEST (num) values (5555522)
I'am searching for a way to convert the integer "5555522" automatically into the number(5,2) value so that the record contains 55555.22 instead of 55555. Is there some kind of function like "setscale(5555522, 2)" which just interprets the last 2 numbers as decimal place?
I already checked the to_number() Funktion in the Oracle docs. But it expects a proper formatted inputstring like to_number('55555.22', 99999D99) which is not suitable in my case.

Oracle should do that implicitly for you, after you divided by 100 :
insert into TEST (num) values (5555522/100)
EDIT : Like you said, it wont fit, you would need to change your table in order to do it :
create table TEST (num number(7,2))

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

Determining input datatype Oracle/PLSQL

I am writing a PLSQL 'INSTEAD OF INSERT' Trigger whereby the ID field (GID) can be inserted as either a string or a number. If the GID value is a string I would like to attempt to convert that into the correct GID (number) otherwise if a number is input the script will continue.
The part I am struggling with here is determining the datatype of ':New.CHART_GID' - is this possible in PLSQL? I can't check for chars in the string as the string may only contain numbers in some instances.
Thanks.
You can use TRANSLATE to check if there is something other as numbers:
CREATE OR REPLACE TRIGGER trigger_name
INSTEAD OF INSERT
ON table_name
FOR EACH ROW
DECLARE
vGID INTEGER;
...... other things
BEGIN
IF :New.CHART_GID is not null AND TRANSLATE(:New.CHART_GID,'0123456789',' ') is null THEN
vGID := TO_NUMBER(:New.CHART_GID);
.... do what you want with number
ELSE
... do what you want with not number
END IF;
.... other things
END;
CHART_GID have to be varchar2 in the view
I realise what I was trying to achieve was actually not possible. The solution for me was actually to join the Chart_no into the view and insert into either that field of the GID. If I input a Chart_no the GID field would be automatically populated and the same for if I input a GID.

Oracle order by varchar2 with numeric values in it

I have an issue where a Oracle DB column(say 'REF_NO') is VARCHAR2 and carries values similar to the ones below
If I do an ORDER BY REF_NO I get this:
LET-2-1
LET-2-10
LET-2-11
LET-2-2
LET-2-3
Which makes sense because the values are being treated as characters. I have been asked to change this so that the returned results are ordered like this:
LET-2-1
LET-2-2
LET-2-3
LET-2-10
LET-2-11
I cannot guarantee the format of these values either so I cannot really see how I can use regex or sub-string as it's a completely free text entry for users to enter values. The example above just happens to be what the requested data looks like. Other data could be completely different.
I cannot see how this is possible, so was hoping for some suggestions.
Additional information
To add to the complexity, here are some more examples from other customers:
Customer 1: OB 12, WE-11, WAN-001
Customer 2: P4, D1, W9
Customer 3: NTT-33A, RLC-33L, ARR-129B
Here are the steps
create table test01 (c varchar2(30));
insert into test01 values ('LET-2-1');
insert into test01 values ('LET-2-10');
insert into test01 values ('LET-2-2');
Query
select * from test01
order by to_number(SUBSTR(C,INSTR(C,'-',1)+1,INSTR(C,'-',1,2)-INSTR(C,'-',1)-1)),
to_number(SUBSTR(C,INSTR(C,'-',-1)+1));
Assuming all the values are having structure of -- - in the above query I try to extract numbers and converted to number in order by clause.
select * from TABLE
ORDER BY LENGTH(REF_NO), REF_NO
first you need to order by length and then order by REF_NO

SQL Insert syntax with max(value)+1

Using Oracle DB
Trying to create logic where when inserting a new row the logic checks if there is an existing numerical value. If there is a value then the logic would perform a max(value)+1. If there is no value then INSERT '1'.
I would suggest that you use a sequence instead of looking for the max value + 1.
A sequence would take care of the incrementing for you. http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_6015.htm
Example:
CREATE SEQUENCE MY_SEQ START WITH 1 INCREMENT BY 1;
Insert like
INSERT INTO MY_TABLE (ID, WIDGET) VALUES (NEXTVAL FOR MY_SEQ, 'asdf');

Generate automatic Id

I am making a web application which uses a database in which I have a field I_ID which i want to automatically increment like I0 then I1 then I2 and so on with each record insertion in the database.
To achieve it I made a trigger for this table.But its not working fine.What can be the reason.Please help
My Trigger T1:
CREATE OR REPLACE TRIGGER "T1"
before
insert on "TBINDIVIDUAL"
for each row
declare
x varchar2(10);
mx varchar2(13);
mx2 varchar2(13);
y number(3);
begin
x:=:new.I_ID;
mx:=substr(x,1,1);
select max(I_ID) into mx2 from tbindividual where I_ID like mx||'%';
y:=to_number(substr(mx2,2));
:new.I_ID:=mx||to_char(y+1);
end t1;
/
EDITED :
As i do by answer
CREATE OR REPLACE TRIGGER "TBINDIVIDUAL_T1"
BEFORE
insert on "TBINDIVIDUAL"
for each row
begin
:new.I_ID = SEQ1.nextval;
end;
/
But it give two errors
Encountered the symbol "=" when expecting one of the following: := . ( # % ; indicator
Encountered the symbol "END"
Please help
So Oracle is not SQL Server...
if you want to get unique ID's, you need to populate them from a sequence.
for creating a sequence use:
create sequence myseq;
and in your code use (depends on the version):
:new.I_ID := myseq.nextval;
or
select myseq.nextval into :new.I_ID from dual;
the problem your code doesn't work is what :new and :old means...
I would recommend you reading about their meaning...
Hope I've been helpful...
Because of the discussion in the comments - here is a full example:
for this table:
CREATE TABLE test (A number);
to add a unique, sequential ID you need to first create a sequence:
CREATE SEQUENCE myseq;
and a trigger:
CREATE OR REPLACE TRIGGER "T1"
before
insert on "test"
for each row
begin
:new.I_ID := myseq.nextval;
end t1;
/
by the way - I would recommend to check before substituting :new.I_ID, if it is null or not, cause sometimes in upgrades people add a unique ID from an external resource.. (such as them getting a unique number from the sequence themselves...)
you can read more about sequences here:
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_6015.htm#SQLRF01314
sorry for the way the code is displayed.. need to learn how to write code here...
One more thing - In Oracle - you cannot create such a PL/SQL to increase existing counter without locks.
Concurrent queries might run the first query in the PL/SQL simultaneously, which means multiple sessions will get the same I_ID.
Also notice that in your code you queried the max on varchar, which is not the same as max on number...
Adding concatenated text is unrelated to the unique ID. In your case it will look like:
:new.I_ID = substr(:new.I_ID,1,1)||to_char(myseq.nextval);
assuming x is being inputted with the char you want..

Resources