Sysdate+days as default value in table column - Oracle - oracle

I'm working on my table which is supposed to store data about rented cars.
And there are 3 important columns:
RENT_DATE DATE DEFAULT TO_DATE (SYSDATE, 'DD-MM-YYYY'),
DAYS NUMBER NOT NULL,
RETURN_DATE DATE DEFAULT TO_DATE(SYSDATE+DAYS, 'DD-MM-YYYY')
My problem is that RETURN_DATE column is giving me error:
00984. 00000 - "column not allowed here"
What i want is that RENT_DATE set automatically date when record is added.
DAYS column is to store for how much days someone is renting car.
And the last column should store date of when car should be returned.
Thank you for any type of help.

This doesn't make sense:
DEFAULT TO_DATE (SYSDATE, 'DD-MM-YYYY')
SYSDATE is already a date. TO_DATE requires a char, so this takes a date, Oracle implicitly turns the date into a char, and then TO_DATE converts it back to a date. This is risky/unreliable because it uses a hardcoded date format to operate on a date that has been implicitly turned to a string using the system default format, which might one day not be DD-MM-YYYY (you're building a latent bug into your software)
If you want a date without a time on it use TRUNC(SYSDATE)
The other problem doesn't make sense either: you're storing a number of days rented for and also the return date, when one is a function of the other. Storing redundant data becomes a headache because you have to keep them in sync. My person class stores my birthdate, and I calculate how old I am. I don't store my age too and then update my table every day/year etc
Work out which will be more beneficial to you to store, and store it, then calculate the other whenever you want it. Personally I would store the return date as it's absolute, rather than open to interpretation of "is that working days, calendar days? what about public holidays? if the start date is jan 1 and the rental is for 10 days, is the car brought back on the 10th or the 11th?"
If you're desperate to have both columns in your DB consider using a view to calculate it or a function based column (again, to calculate one from the other) so they stay in sync
All in, you could look at this:
create table X(
RENT_DATE DATE DEFAULT TRUNC(SYSDATE) NOT NULL,
RETURN_DATE DATE NOT NULL,
DAYS AS (TRUNC(RETURN_DATE - RENT_DATE) + 1)
)
I put the days as +1 because to me, a car taken on the 1st and returned on the second is 2 days, but you might want to get more accurate - if it's taken on the first and returned before 10am on the second then it's one day otherwise it's 2 etc...

Use a virtual column:
CREATE TABLE table_name (
RENT_DATE DATE
DEFAULT TRUNC( SYSDATE )
CONSTRAINT table_name__rent_date__nn NOT NULL
CONSTRAINT table_name__rent_date_chk CHECK ( rent_date = TRUNC( rent_date ) ),
DAYS NUMBER
DEFAULT 7
CONSTRAINT table_name__days__nn NOT NULL,
RETURN_DATE DATE
GENERATED ALWAYS AS ( RENT_DATE + DAYS ) VIRTUAL
);
Then you can insert values:
INSERT INTO table_name ( rent_date, days ) VALUES ( DEFAULT, DEFAULT );
INSERT INTO table_name ( rent_date, days ) VALUES ( DATE '2020-01-01', 1 );
And:
SELECT * FROM table_name;
Outputs:
RENT_DATE | DAYS | RETURN_DATE
:------------------ | ---: | :------------------
2020-09-12T00:00:00 | 7 | 2020-09-19T00:00:00
2020-01-01T00:00:00 | 1 | 2020-01-02T00:00:00
db<>fiddle here

Related

Oracle -- Datatype of column which can store value "13:45"

We need to store a value "13:45" in the column "Start_Time" of an Oracle table.
Value can be read as 45 minutes past 13:00 hours
Which datatype to be used while creating the table? Also, once queried, we would like to see only the value "13:45".
I would make it easier:
create table t_time_only (
time_col varchar2(5),
time_as_interval INTERVAL DAY TO SECOND invisible
generated always as (to_dsinterval('0 '||time_col||':0')),
constraint check_time
check ( VALIDATE_CONVERSION(time_col as date,'hh24:mi')=1 )
);
Check constraint allows you to validate input strings:
SQL> insert into t_time_only values('25:00');
insert into t_time_only values('25:00')
*
ERROR at line 1:
ORA-02290: check constraint (CHECK_TIME) violated
And invisible virtual generated column allows you to make simple arithmetic operations:
SQL> insert into t_time_only values('15:30');
1 row created.
SQL> select trunc(sysdate) + time_as_interval as res from t_time_only;
RES
-------------------
2020-09-21 15:30:00
Your best option is to store the data in a DATE type column. If you are going to be any comparisons against the times (querying, sorting, etc.), you will want to make sure that all of the times are using the same day. It doesn't matter which day as long as they are all the same.
CREATE TABLE test_time
(
time_col DATE
);
INSERT INTO test_time
VALUES (TO_DATE ('13:45', 'HH24:MI'));
INSERT INTO test_time
VALUES (TO_DATE ('8:45', 'HH24:MI'));
Test Query
SELECT time_col,
TO_CHAR (time_col, 'HH24:MI') AS just_time,
24 * (time_col - LAG (time_col) OVER (ORDER BY time_col)) AS difference_in_hours
FROM test_time
ORDER BY time_col;
Test Results
TIME_COL JUST_TIME DIFFERENCE_IN_HOURS
____________ ____________ ______________________
01-SEP-20 08:45
01-SEP-20 13:45 5
Table Definition using INTERVAL
create table tab
(tm INTERVAL DAY(1) to SECOND(0));
Input value as literal
insert into tab (tm) values (INTERVAL '13:25' HOUR TO MINUTE );
Input value dynamically
insert into tab (tm) values ( (NUMTODSINTERVAL(13, 'hour') + NUMTODSINTERVAL(26, 'minute')) );
Output
you may either EXTRACT the hour and minute
EXTRACT(HOUR FROM tm) int_hour,
EXTRACT(MINUTE FROM tm) int_minute
or use formatted output with a trick by adding some fixed DATE
to_char(DATE'2000-01-01'+tm,'hh24:mi') int_format
which gives
13:25
13:26
Please see this answer for other formating options HH24:MI
The used INTERVAL definition may store seconds as well - if this is not acceptable, add CHECK CONSTRAINT e.g. as follows (adjust as requiered)
tm INTERVAL DAY(1) to SECOND(0)
constraint "wrong interval" check (tm <= INTERVAL '23:59' HOUR TO MINUTE and EXTRACT(SECOND FROM tm) = 0 )
This rejects the following as invalid input
insert into tab (tm) values (INTERVAL '13:25:30' HOUR TO SECOND );
-- ORA-02290: check constraint (X.wrong interval) violated

Split Date from Oracle Form to DB

I have a table with columns(year,day-month) -date type- in my database.
and a form with a text field for the user to enter a date.
how can I split the entered date to save it on db as following
year day_month
---- ---------
2018 03-04
I tried SUBSTR(TO_CHAR(TO_DATE(block.field)) in a trigger ,
but it didn't work bcz the column type is date, and I tried to add TO_DATE() as outer but the result was
year day_month
---------- ----------
03-04-2018 03-04-2018
How can I do it without changing my columns type?
I'd suggest you NOT to do that. Always store DATE values into DATE datatype columns. ALWAYS.
Later, if you want to present them differently, apply appropriate functions (such as TO_CHAR) to those values and display them any way you want.
In your example, that would be
TO_CHAR(date_column, 'yyyy') year
or
EXTRACT (year from date_column) year
and
TO_CHAR(date_column, 'dd-mm') day_month
[EDIT]
Once again (to repeat what I've said in a comment): the fact that you named columns in the database "year" (whose datatype is DATE) and "day_month" (whose datatype is also DATE) is completely useless.
Right now is (dd.mm.yyyy hh24:mi) 03.04.2018 10:32.
DATE datatype contains both date and time, so - how do you plan to put "2018" into the "year" column? What will you do with its month/day/hour/minutes/seconds component? It can't just "vanish", has to have some value. Is it the first of January at 00:00:00? Or what?
The same goes to your "day_month" column - it'll contain year, as well as hours/minutes/seconds, whether you want it or not.
Let's start with the "year": if you want to extract it from the Form item, that would be TO_CHAR, such as
to_char(:block.some_item, 'yyyy')
which results in a string, '2018'. You can't store it into a DATE datatype column, so you have to apply TO_DATE to it:
to_date(to_char(:block.some_item, 'yyyy'), 'yyyy')
and it will result in 01.04.2018 00:00:00 >>> see? Day, month, hours ... everything is here.
The alternative is to create those columns as VARCHAR2, but that's even worse.
Seriously, don't do that.
Try the following and make the necessary changes in Oracle Forms, substitute block and columns names instead of variables.
DECLARE
p_year VARCHAR2 (8);
p_date VARCHAR2 (8);
BEGIN
SELECT TO_CHAR (SYSDATE, 'YYYY') INTO p_year FROM DUAL;
SELECT TO_CHAR (SYSDATE, 'DD-MM') INTO p_date FROM DUAL;
DBMS_OUTPUT.put_line ('p_year --> ' || p_year || ' p_date --> ' || p_date);
END;
If your column is a DATE type, expect that it will require you to input a date data also.
In your case, you don't need to split a date. For the YEAR column, if the year value only matters to you, then you can use the TRUNC function
:BLK.YEAR_DATE_FIELD := TRUNC(:BLK.DATE_VALUE, 'YYYY');
and for the MONTH column, just save the date value there.
:BLK.MONTH_DATE_FIELD := :BLK.DATE_VALUE;
Also, maybe you just need to set the format mask of those two fields in Oracle forms. You can set the Format Mask of YEAR field to YYYY and MM-DD to the MONTH field.
The DATE data type is stored dates in tables as 7-bytes
byte 1 - century + 100
byte 2 - (year MOD 100 ) + 100
byte 3 - month
byte 4 - day
byte 5 - hour + 1
byte 6 - minute + 1
byte 7 - seconds+ 1
You CANNOT have a DATE data type that just stores year or month + day; it will always store all the components of the date/time.
So you either store the correct values in each column or you will have to make up values for the components you are not storing and will need to make sure that all the made up values are appropriate for the real values. It is just easier to use the real values in both columns.
So just do:
INSERT INTO your_table(
year,
day_month
) VALUES (
:BLK1.T_DATE,
:BLK1.T_DATE
);
Without splitting the date because a day_month without a year does not make sense (is 29th February a valid date? For the majority of years, no it isn't).
When you want to output it with a format then just format it as a string on output:
SELECT TO_CHAR( year, 'yyyy' ) AS year,
TO_CHAR( day_month, 'dd-mm' ) AS day_month
FROM your_table;

how to change the date to time in oracle 10g

I have to put in STIMING a time when I insert I use TO_DATE function but it give me date not time and it should be time.
This is the table and the code that i use
SQL> select * from shift;
SNO SNAME STIMING
---------- -------------------- ---------
121323 morning 01-APR-17
112232 evening 01-APR-17
665342 afternoon 01-APR-17
SQL> update shift
2 set STIMING= ('07:00:00 HH,MI,SS')
3 where SNO=121323;
set STIMING= ('07:00:00 HH,MI,SS')
*
ERROR at line 2:
ORA-01843: not a valid month
I have to put in STIMING a time
Oracle does not have a TIME datatype. The DATE data type is always stored internally as 7-bytes and is always composed of year (2-bytes) and month, day, hours, minutes and seconds (1-byte each).
You cannot not have a year, month or day component of a DATE.
If you want a time on its own then you will have to store it as a different data type or store the year/month/day and ignore that component.
When you are SELECTing the STIMING column it is not showing the time component. You can change this by changing the default date format which is set in the NLS_DATE_FORMAT session parameter.
You can review this parameter using:
SELECT VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT';
You can set this value within your current session using:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
(Note: this does not change the value for any other users.)
When you insert the date you can use:
INSERT INTO shift ( SNO, SNAME, STIMING)
VALUES ( 121323, 'morning', TO_DATE( '01-APR-2017 07:00' DD-MON-YYYY HH24:MI' ) )
Or, an ANSI TIMESTAMP literal (which will be implicitly cast to the DATE format of the column):
INSERT INTO shift ( SNO, SNAME, STIMING)
VALUES ( 121323, 'morning', TIMESTAMP '2017-04-01 07:00:00' )
I suggest you to avoid updates, change your insert part from to_date with no formatting param to to_date( colname, 'DD-MON-YY HH24:MI:SS')

Oracle date seems equals

there is a table INCASSO in my database:
CREATE TABLE "GEC_AP"."INCASSO"
("ID_INCASSO" VARCHAR2(50 BYTE) NOT NULL ENABLE,
"ID_FATTURA" VARCHAR2(50 BYTE) NOT NULL ENABLE,
"ID_PIANO_RATE" VARCHAR2(22 BYTE) DEFAULT -1 NOT NULL ENABLE,
"DATA_ESECUZIONE" DATE DEFAULT SYSDATE NOT NULL ENABLE,
...)
The primary key includes four fields:
CONSTRAINT "PK_INCASSO" PRIMARY KEY ("ID_INCASSO", "ID_FATTURA", "ID_PIANO_RATE", "DATA_ESECUZIONE")
It seems there is a duplicated record when I run the following query:
select id_incasso, id_fattura, id_piano_rate, data_esecuzione
from incasso
where id_incasso = 'TO_20110521258225'
But with another query, 0 records are extracted:
select id_incasso, id_fattura, id_piano_rate, data_esecuzione, count(*)
from incasso where id_incasso = 'TO_20110521258225'
group by id_incasso, id_fattura, id_piano_rate, data_esecuzione
having count(*) > 1
The database is on Oracle 11.2.0.1.0 and I'm using SQL Developer 4.1.1.19.
In SQL Developer, the date format is:
I would to know if the records are different or there is a format date problem in the editor. If the records are different based on the date, in which part of the date they are different? If it's a format date problem in the editor, how can I fix it?
Change the date format to DD-MON-YYYY HH24:MI:SS and you are likely to see the difference in that the dates have different centuries.
Using RR to format the year can hide that one date is 1911 and the other is 2011
Try:
SELECT TO_CHAR( DATE '2011-01-01', 'RR-MM-DD' ),
TO_CHAR( DATE '1911-01-01', 'RR-MM-DD' )
FROM DUAL
Both will output the same although they are different dates and will not be grouped together.
If the dates are still the same then look for additional spaces or other hidden characters in the strings; you can use LENGTH() to check the size of the strings or DUMP() to get the byte values of the contents:
select id_incasso,
id_fattura,
LENGTH( id_fattura ) AS f_length,
id_piano_rate,
LENGTH( id_piano_rate ) AS pr_length,
TO_CHAR( data_esecuzione, 'YYYY-MM-DD HH24:MI:SS' ) AS data_esecuzione
from incasso
where id_incasso = 'TO_20110521258225'
I've changed the date format used in SQL Developer to DD-MON-YYYY HH24:MI:SS
and the following query:
select id_incasso, id_fattura, id_piano_rate, data_esecuzione from incasso where id_incasso = 'TO_20110521258225'
show that the difference is in the year:
Thanks everyone.

Which Data types are correct for storing numeric year input and numeric month in Oracle?

I am learning oracle 11g. I need to create columns to store Year and Month in the following sample format:
Year: 2015
Month: 6
I saw Date Time data type which takes whole date only .Also Number type may allow invalid year and month. But I want them in the given form while avoiding invalid month and year. Please tell me how to fix it.thanks
Updates: is this okay for such inputs?
CREATE TABLE FOOBAR (YYYY DATE, MM DATE);
The best solution is to store dates in DATE columns. Oracle has some pretty neat date functions, and you'll find it easy to work with storing the first of the month in a single DATE column. Otherwise you'll find yourself constantly extracting elements from other dates or cluttering your code with TO_CHAR() and TO_DATE() calls. Find out more.
However, if you have a rigid requirement, you can use strong typing and check constraints to avoid invalid months:
CREATE TABLE FOOBAR (
YYYY number(4,0) not null
, MM number(2,0) not null
, constraint foobar_yyyy_ck check (yyyy != 0)
, constraint foobar_mm_ck check (mm between 1 and 12)
);
This won't do what you want because it will default the missing elements:
CREATE TABLE FOOBAR (YYYY DATE, MM DATE);
We can't store just a year or just a month in DATE columns.
Use the DATE data type..
and when perform insert operation onto your db.. use
TO_DATE ('November 13, 1992', 'MONTH DD, YYYY')
For input and output of dates, the standard Oracle date format is DD-MON-YY, as follows:
'13-NOV-92'
perform insert operation/query like this:
INSERT INTO table_name (name, created_at) VALUES
('ANDY', TO_DATE ('November 13, 1992', 'MONTH DD, YYYY'));
Here is link to the guide as well:
https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#i1847
If you want to store month and year separately in the db you may use NUMBER & NUMBER(n)
https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#i22289
Hope this helps..

Resources