Trouble inserting data into tables ORA-01722: invalid number - sql

I'm trying to insert it into a table called bill but I keep getting errors no matter how much I what I do.
Below is the code that I'm using, when I tried replacing the total with NULL (for the sake of testing), it went through and inserted into the table. When I try to use any number no matter how long I keep getting "ORA-01722: invalid number"
insert into Bill ( Bill_code, Total, Start_date, End_date, Customer_ID )
VALUES('1373','5200','02-03-2022','02-05-2021','6724');
The number datatype has a precision of 16 with a scale of 2 and it's nullable.

ORA-01722: invalid number clearly states that this is an Oracle error; what is that postgres tag doing here?
In Oracle - as far as I managed to recreate your test case (as you didn't post table description), it works correctly.
You should really use proper datatypes:
as long as bill_code or customer_id may be strings,
total certainly isn't (you said it is a number), while
dates should be exactly that - DATE datatype
in that case, use date literal (as my example shows) or to_date function with appropriate format model. Don't rely on implicit datatype conversion. What is 02-03-2022? Is it 2nd of March or 3rd of February? Could be both.
So:
SQL> CREATE TABLE bill
2 (
3 bill_code VARCHAR2 (10),
4 total NUMBER (16, 2),
5 start_date DATE,
6 end_date DATE,
7 customer_id VARCHAR2 (10)
8 );
Table created.
SQL> INSERT INTO Bill (Bill_code,
2 Total,
3 Start_date,
4 End_date,
5 Customer_ID)
6 VALUES ('1373',
7 5200,
8 DATE '2022-03-02',
9 DATE '2021-05-02',
10 '6724');
1 row created.
SQL>

If your column type is not varchar or any character based one, do not use quotes for inserting numbers.
insert into Bill ( Bill_code, Total, Start_date, End_date, Customer_ID ) VALUES('1373',5200,'02-03-2022','02-05-2021','6724');

Related

Automatically Populate Incremented Day

In my table I have 3 dates that are important:
Scrap_Date
Due_Date
Follow_Up_Date
The Scrap Date is entered into a form. I would like to have the form to where once the "Scrap_Date" is entered, "Due_Date" would automatically populate a date 7 days later, and "Follow_Up_Date" would automatically populate t a date 14 days later.
I still want these dates to display on the form, but for them to automatically populate to these dates without being able to be changed.
What is the best way to go about this?
I've tried setting up a Select List, but struggled with what to code with SQL.
I have also tried this to no success:
select SCRAP_DATE,
DUE_DATE,
FOLLOW_UP_DATE,
from SCRAP_BODY_SYSTEM
where DUE_DATE = SCRAP_DATE + 7
AND FOLLOW_UP_DATE = SCRAP_DATE + 14
I appreciate any help, thank you!
Not sure about APEX GUI issues but two points:
you seem to select rows which already satisfy your "T, T+7, T+14" condition. You might rather want to somehow derive them, for instance compute in select clause?
the syntax for date addition is
select SCRAP_DATE, SCRAP_DATE + interval '7' day, SCRAP_DATE + interval '14' day
from SCRAP_BODY_SYSTEM
You shouldn't be doing it that way. If due_date and follow_up_date are always 7/14 days after scrap_date, then what's their purpose? You can always calculate them when you need them.
If you still want to have them in the table, make them virtual (see lines #5 and 6); doing so, Oracle will do everything for you.
SQL> create table test
2 (id number generated always as identity,
3 scrap_date date,
4 --
5 due_date date as (scrap_date + 7),
6 follow_up_date date as (scrap_date + 14),
7 --
8 constraint pk_test primary key (id)
9 );
Table created.
(just to know what is what; you don't have to do this):
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
In your Apex form, you'd insert only scrap_date:
SQL> insert into test (scrap_date) values (date '2022-06-15');
1 row created.
Table contents is then:
SQL> select * from test;
ID SCRAP_DATE DUE_DATE FOLLOW_UP_
---------- ---------- ---------- ----------
1 15.06.2022 22.06.2022 29.06.2022
SQL>
See? Everything is already set.

Calculating and store derived attribute in Oracle Sql Developer

I am just trying to calculate and store age attribute derivedly from dob(date of birth). How can ı do that in Oracle SQL Developer?
CREATE TABLE Patient (
dob DATE,
age NUMBER(3));
I mean when de dob inserted like that 01/01/2000 the age will automatically calculated to 21.
No, you're planning to do it in a wrong way. Why would you so badly want to do that?
It's the same as people - who fill their profile - say "I've got 5 years of experience with Oracle". That was probably true at the moment of writing that text, but - is it still valid now? Two years later it should be "I've got 7 years of experience".
So, what kind of information would be storing fixed age into that column? That person was 21 years old at the moment of insert, but they won't stay forever young. Believe me, I know.
You were suggested to create a virtual column. Well, you can't. Why? Because - in order to calculate someone's age - you have to refer to today's date. Function that returns it is SYSDATE. Bad luck - it is not deterministic, which means that it doesn't return the same value each time you call it with the same parameters. It doesn't accept any, that's true, but it doesn't matter. If you try it, it'll fail:
SQL> create table patient
2 (id number constraint pk_pat primary key,
3 date_of_birth date not null,
4 age number generated always as
5 (round(months_between(sysdate, date_of_birth)/12, 0))
6 virtual
7 );
(round(months_between(sysdate, date_of_birth)/12, 0))
*
ERROR at line 5:
ORA-54002: only pure functions can be specified in a virtual column expression
SQL>
So, what can you do? You can create a view.
SQL> create table patient
2 (id number constraint pk_pat primary key,
3 date_of_birth date not null
4 );
Table created.
SQL> create or replace view v_patient as
2 select id,
3 date_of_birth,
4 round(months_between(sysdate, date_of_birth)/12, 0) as age
5 from patient;
View created.
SQL>
Let's test it.
SQL> insert into patient (id, date_of_birth) values (1, date '2000-01-01');
1 row created.
SQL> select * from v_patient;
ID DATE_OF_BI AGE
---------- ---------- ----------
1 01.01.2000 21
SQL>
Looks OK to me.

Writing a Trigger to find and fill the age of a patient whenever a patient record is inserted into patients table

In this question, I have to add value of age with the help of trigger.
please help me implement this question.
create or replace trigger ia_patient
after insert on patient
for each row
enable
declare
age_value number(10);
begin
DBMS_OUTPUT.PUT_LINE('Please Insert Age');
update patient set age=&age_value where ??;
end;
I am not sure what I should write after "where"
Unless it is a homework question, it really doesn't make much sense as "age" depends on current date.
Anyway, see if this helps.
SQL> create table patient
2 (id number primary key,
3 date_of_birth date,
4 age number
5 );
Table created.
Trigger: calculate age as months between sysdate and date of birth divided by 12 (as there are 12 months in a year); certainly, this is just an approximate value, but - as far as I understood - your task isn't to correctly calculate age, but to learn how to use triggers.
SQL> create or replace trigger ia_patient
2 before insert on patient
3 for each row
4 begin
5 :new.age := round(months_between(sysdate, :new.date_of_birth) / 12);
6 end;
7 /
Trigger created.
Testing:
SQL> insert into patient (id, date_of_birth) values (2, date '2000-10-05');
1 row created.
SQL> select * from patient;
ID DATE_OF_BI AGE
---------- ---------- ----------
2 2000-10-05 20
SQL>
This is written as a frame challenge to the question.
Don't use a trigger; if you do it'll insert the age now and then tomorrow, or in 6 months, or a year the person will have a birthday and your table will be incorrect. This should be something you calculate in a query at the time you want the data and could be put into a view.
CREATE TABLE people (
id INTEGER
GENERATED AS IDENTITY
CONSTRAINT people__id__pk PRIMARY KEY,
name VARCHAR2(50)
NOT NULL,
date_of_birth DATE
NOT NULL
);
Then you can create a view to calculate the ages:
CREATE VIEW people_ages ( id, name, date_of_birth, age ) AS
SELECT id,
name,
date_of_birth,
FLOOR( MONTHS_BETWEEN( SYSDATE, date_of_birth ) / 12 )
FROM people;
Which, if you have the sample data:
INSERT INTO people ( name, date_of_birth )
SELECT 'Alice', DATE '1970-01-01' FROM DUAL UNION ALL
SELECT 'Bob', DATE '2020-10-21' FROM DUAL UNION ALL
SELECT 'Carol', DATE '2000-10-21' FROM DUAL;
Then the output from the view would be:
SELECT * FROM people_ages;
ID | NAME | DATE_OF_BIRTH | AGE
-: | :---- | :------------------ | --:
1 | Alice | 1970-01-01 00:00:00 | 50
2 | Bob | 2020-10-21 00:00:00 | 0
3 | Carol | 2000-10-21 00:00:00 | 20
db<>fiddle here
Your trigger has serious defects. Despite being a totally inappropriate use of a trigger I'll go over them.
Attribute: Age. Lets just say others have sufficiently covered it. But i will return to it.
DBMS_OUTPUT: This is not output when issued. The pl/sql engine does not even output this at all. It builds an internal buffer which can later be read back and processed by the client after the pl/sql has completed. However, there is no requirement that the client do so. Typically used for debugging purposes and not available in production system.
&age_value: This is an attempt at an interactive processing. Pl/sql is not and cannot do interactive processing. This is called a substitution variable and is totally the responsibly of the client. The client sees the &... and prompts for a value. It then physically alters the statement to contain that value. For example if you reply 42 to the prompt what is sent to the compiler is age=42. The compiler actually never sees &age_value.
Update: you CAN NOT do this; it will throw the exception "ORA-04091: table ... is mutating, trigger/function may not see it". Within a trigger you cannot issue DML on the table that caused the trigger to fire. Moreover it is completely unnecessary.
where ??: Since you cannot have the update statement this is moot.
In a trigger you refer to table columns through the pesudo rows :new and/or :old. So assuming you need to stay with a trigger you rewrite as (following assumes a date_of_birth column (dob) name being inserted):
create or replace trigger ia_patient
after insert on patient
for each row
enable
begin
:new.age := trunc(months_between(sysdate, :new.dob)/12);
end;
However the problem being age is now a static value. Which will need regular updates to keep current. A much better approach just let Oracle do the calculation when needed with a view as suggested by #MT0 and abandon the trigger altogether.

About dual table structure in Oracle SQL *Plus

We know that "Dual" is a temporary table which exactly contains 1 column whose name is "dummy" which is of "varchar2(1)" type that has 1 single row. The value of that record is "X". The varchar2 has size of 1 which means it should not allow more than a single character.
Now my question is: If it is of varchar2 type, then why it can hold any datatype temporarily AND If we insert characters more than 1 (size), how this is possible for it (dual) to accept it ? Example:
SQL> desc dual
Name Null? Type
------------------------------- -------- ----
DUMMY VARCHAR2(1)
SQL> select sysdate from dual;
SYSDATE
---------
22-JAN-13
SQL> select 5*5 result from dual;
RESULT
---------
25
SQL> select 'Ankita' as "Name" from dual;
Name
------
Ankita
Clearly "SYSDATE" is of DATE type (not varchar2), "RESULT" is of NUMBER type (not varchar2). Also 'Ankita' is more than 1 single character, i.e., 6 characters. This should contradict the structure that varchar2 is holding only 1, and supporting 6 too..
The types and sizes of columns only come into play when you extract the data from them. It's true that if you select the dummy column, it will only give you what is in that column.
But, when you're selecting something unrelated to the column data, such as 5*5 or 'Ankita', they have no such restrictions.
I think your misunderstanding stems from your snippet:
why it can hold any datatype temporarily AND If we insert characters more than 1 (size), how this is possible for it (dual) to accept it ?
The truth is, the column doesn't accept it. Selecting 5*5 does not attempt to place that data into the table somewhere, it just evaluates it as-is. It's no different to having a table with:
users:
id
name
and performing:
select 42, 3.14159, id, name from users
For every row selected from, you will see the constant values 42 and 3.14159, alongside the data extracted from the two specified columns.

Oracle — separate time and date

I have a question with Oracle (I've installed Oracle 11g Express Edition).
I want to insert values for 'date' and 'time', but I cannot separate them.
create table Match
(
numMatch number(2) constraint PKMatch primary key,
dateM date,
heureM date,
numE_Eq number(2),
numE_Eq2 number(2),
nomTerrain varchar2(30)
);
--"tools"=>"preferences"=>"format de date:DD/MM/YYYY HH24:MI:SS"
insert into Match values (1,to_date
('10/12/2010','DD/MM/YYYY'),to_date('15:00:00','HH24:MI:SS'),1,3,'Stade Argentina'
);
result:
dateM: 10/12/2010 00:00:00
heureM: 01/11/2012 15:00:00
PS: I've tried to_char instead of to_date, but it didn't work at all.
Yes, I'm aware of that 'DATE datatype contains both date and time', but it's the prof who insists showing date and time separately in the table,
and I've seen your solutions before, but for me, it's a query, not to 'insert values' in the table.
So I'd like to know how I can have a table directly presenting date and time.
Oracle doesn't have a TIME datatype. You can store a DATE with a time component, and just query based on time, and display based on time.
select to_char(my_date_field, 'HH24:MI:SS')
from my_table
where to_date(my_date_field, 'HH24:MI') = '18:51';
Alternatively, you can store seconds from midnight as an integer, and calculate the time of day from that. It will also make querying for range times easier I think.
Also, within a session, execute the following to have all dates formatted the way you wish:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'
Another way to represent a TIME equivalent type in Oracle is with the INTERVAL type, such as:
SQL> CREATE TABLE foo (
bar INTERVAL DAY(0) TO SECOND(3)
);
This would allow the storage of a time period with 0 precision of the DAY component, and 3 decimal points for the SECOND component. An INSERT example is:
SQL> INSERT INTO foo VALUES ('0 01:01:01.333');
What's great about this approach is that it automatically presents the results of a SELECT in an intuitive format without the need for conversion:
SQL> SELECT * FROM foo;
BAR
---------------------------------------------------------------------------
+0 01:01:01.333
but it's the prof who insists showing date and time separately in the table
While this sounds like a pretty stupid requirement, one thing you could do is to create two computed columns that show the date and time as varchar columns:
create table match
(
nummatch number(2) constraint pkmatch primary key,
the_date date,
datem generated always as to_char(the_date, 'yyyy-mm-dd'),
heurem generated always as to_char(the_date, 'hh24:mi')
nume_eq number(2),
nume_eq2 number(2),
nomterrain varchar2(30)
);
insert into Match (nummatch, the_date, nume_eq, nume_eq2, nomterrain)
values
(1,to_date('10/12/2010 15:00:00','DD/MM/YYYY hh24:mi:ss'),1,3,'Stade Argentina');
Then a
select *
from match;
will return:
NUMMATCH | THE_DATE | DATEM | HEUREM | NUME_EQ | NUME_EQ2 | NOMTERRAIN
---------+---------------------+------------+--------+---------+----------+----------------
1 | 2010-12-10 15:00:00 | 2010-12-10 | 15:00 | 1 | 3 | Stade Argentina
Alternatively you could just create a view on the table that separates the date and time using to_char()
Oracle DATE type includes both DATE and TIME information (because it pre-dates the SQL-92 standard when the standard DATE, TIME and TIMESTAMP types were added). So, you can't separate them in the table; there's no reason to do so, either. You can, if you so desire, create a view which presents the DATE field as separate date-only and time-only display fields.