My table looks like below which is declared in VARCHAR2:
YMD
20101010
20101112
20100231
20150101
20160101
I have to check for valid dates and filter future dates from sysdate, which are in valid format.
I write the function as below to check for valid dates:
create or replace FUNCTION VALIDATE_DATE (p_string in string) return date is
begin
return to_date(p_string, 'YYYYMMDD');
exception when others then
begin
return to_date(p_string, 'YYYY-MM-DD');
exception when others then
begin
return to_date(p_string, 'RR-MON-DD');
exception when others then
return null;
end;
end;
end;
and written this query to check for valid dates and replace with null for invalid dates
select ymd, VALIDATE_DATE(ymd) as Valid
from temp
and to check future dates I wrote the following query, but it throws error
ORA-01839
select ymd
from temp
where validate_date(ymd)='YES'
and to_date(ymd,'yyyymmdd')>sysdate
How to check future dates in my table if exists?
I will rather fix the design issue as a permanent fix rather than wasting time on the workaround.
Firstly, NEVER store DATE as VARCHAR2. All this overhead is due to the fact that your design is flawed.
'20100231'
How on earth could that be a valid date? Which calendar has a 31 days in FEBRUARY?
Follow these steps:
Add a new column with DATE DATA TYPE.
Update the new column with date values from the old column using TO_DATE.
Do the required DATE arithmetic on the new DATE column, or handle this in the UPDATE statement in step 2 itself.
Drop the old column.
Rename the new column to the old column.
UPDATE Adding a demo
Setup
SQL> CREATE TABLE t
2 (ymd varchar2(8));
Table created.
SQL>
SQL> INSERT ALL
2 INTO t (ymd)
3 VALUES ('20101112')
4 --INTO t (ymd)
5 -- VALUES ('20100231')
6 INTO t (ymd)
7 VALUES ('20150101')
8 INTO t (ymd)
9 VALUES ('20160101')
10 SELECT * FROM dual;
3 rows created.
SQL>
SQL> COMMIT;
Commit complete.
SQL>
Add new column:
SQL> ALTER TABLE t ADD (dt DATE);
Table altered.
SQL>
DO the required update
SQL> UPDATE t
2 SET dt =
3 CASE
4 WHEN to_date(ymd, 'YYYYMMDD') > SYSDATE
5 THEN NULL
6 ELSE to_date(ymd, 'YYYYMMDD')
7 END;
3 rows updated.
SQL>
SQL> COMMIT;
Commit complete.
SQL>
Let's check:
SQL> SELECT * FROM t;
YMD DT
-------- ---------
20101112 12-NOV-10
20150101 01-JAN-15
20160101
SQL>
Drop the old column:
SQL> ALTER TABLE t DROP COLUMN ymd;
Table altered.
SQL>
Rename the new column to old column name
SQL> ALTER TABLE t RENAME COLUMN dt TO ymd;
Table altered.
SQL>
You have just fixed the issue
SQL> SELECT * FROM t;
YMD
---------
12-NOV-10
01-JAN-15
SQL>
Related
Error while trying to insert a query which transforms multiple merged date(eg.20230208065521019355) into proper timestamp format to a new column.
INSERT INTO NEWTABLE2(RC_DATETIME)
SELECT TO_CHAR(TO_TIMESTAMP(RC_TIMESTAMP, 'YYYY-MM-DD HH:MI:SS:FF'), 'YYYY-MM-DD HH:MI:SS.FF')
FROM NEWTABLE;
Upon just executing the SELECT statement I get the query but while including the INSERT I get the error of 'not valid month'.
Data within the RC_TIMESTAMP(VARCHAR) are the merged data which are as follows:
20230208065521019355, 20230208065523019356, 20230208065532019357, etc.
RC_DATETIME has VARCHAR(35) datatype.
I have tried reordering the format of TO_CHAR, 'YYYY-MM-DD HH:MI:SS.FF' to 'Mon-DD-YYYY HH:MI:SS.FF' to name a few.
From what you posted:
Source table:
SQL> CREATE TABLE newtable (rc_timestamp)
2 AS (SELECT '20230208065521019355' FROM DUAL);
Table created.
Target table:
SQL> CREATE TABLE newtable2
2 (rc_datetime VARCHAR2 (35));
Table created.
Insert:
SQL> INSERT INTO newtable2 (rc_datetime)
2 SELECT TO_CHAR (TO_TIMESTAMP (rc_timestamp, 'yyyymmddhh24missff6'),
3 'yyyy-mm-dd hh24:mi:ss:ff')
4 FROM newtable;
1 row created.
However, you'd rather store timestamps into a timestamp column, not as a string. What benefit do you expect? It causes problems in later data processing.
SQL> DROP TABLE newtable2;
Table dropped.
SQL> CREATE TABLE newtable2
2 (rc_datetime TIMESTAMP);
Table created.
SQL> INSERT INTO newtable2
2 SELECT TO_TIMESTAMP (rc_timestamp, 'yyyymmddhh24missff6') FROM newtable;
1 row created.
SQL>
You commented that you still have the "not a valid month" error.
It means that data - at position where TO_TIMESTAMP expects a valid month value (01, 02, ..., 12) - contains something else. What? No idea, you have all the data. Try to find it by selecting a substring (month starts at position 5 and takes 2 places):
SQL> SELECT rc_timestamp, SUBSTR (rc_timestamp, 5, 2) month FROM newtable;
RC_TIMESTAMP MO
-------------------- --
20230208065521019355 02
SQL>
Invalid data is most probably here:
SELECT rc_timestamp
FROM newtable
WHERE SUBSTR (rc_timestamp, 5, 2) NOT BETWEEN '01' AND '12';
Once you find invalid values, you'll decide what to do with it. Maybe you'll ignore those values (so you'd include appropriate where clause into the insert statement), or fix it (somehow; can't tell how as it depends on what you'll find), or ...
If you want to identify invalid values during insert, a simple option is a loop with an inner begin-exception-end block which lets you capture those values and still proceed with other row(s). Something like this:
create table invalid_values as
select id, value from source_table where 1 = 2;
begin
for cur_r in (select * from source_table) loop
begin
insert into newtable2 ...
exception
when others then
insert into invalid_values (id, value) values (cur_r.id, cur_r.value);
end;
end loop;
end;
Once you're done, select * from invalid_value so that you could deal with what's left.
That should be OK as you have 10.000 rows so loop won't take infinite time to complete. True, it will be slower than set-oriented operation, but ... you have to fetch invalid rows, somehow.
I have used this trigger:
CREATE OR REPLACE TRIGGER trg_chk_future
BEFORE INSERT ON your_table
FOR EACH ROW
BEGIN
IF( :new.date_time < sysdate )
THEN
RAISE_APPLICATION_ERROR( -20001, 'date_time must be in the future' );
END IF;
END;
However the current date comes up as an error when entered such as 12/12/2021 (today date) but 13/12/21 and any date after the today date works.
Any ideas what's wrong.
If you really inserted values you wrote in the question, who-knows-what you really inserted. Because, those are strings, not date values. Therefore, Oracle tried to convert them to valid DATE datatype values and - according to what you said - failed.
It means that you should actually insert DATE values, like the following example shows (trigger is exactly the same as you made it):
SQL> create table your_table (date_time date);
Table created.
SQL> CREATE OR REPLACE TRIGGER trg_chk_future
2 BEFORE INSERT ON your_table
3 FOR EACH ROW
4 BEGIN
5 IF( :new.date_time < sysdate )
6 THEN
7 RAISE_APPLICATION_ERROR( -20001, 'date_time must be in the future' );
8 END IF;
9 END;
10 /
Trigger created.
Testing: truncated sysdate is set to midnight (which was in the past, and thus rejected):
SQL> insert into your_table values (trunc(sysdate));
insert into your_table values (trunc(sysdate))
*
ERROR at line 1:
ORA-20001: date_time must be in the future
ORA-06512: at "SCOTT.TRG_CHK_FUTURE", line 4
ORA-04088: error during execution of trigger 'SCOTT.TRG_CHK_FUTURE'
May this year, also in the past:
SQL> insert into your_table values (date '2021-05-25');
insert into your_table values (date '2021-05-25')
*
ERROR at line 1:
ORA-20001: date_time must be in the future
ORA-06512: at "SCOTT.TRG_CHK_FUTURE", line 4
ORA-04088: error during execution of trigger 'SCOTT.TRG_CHK_FUTURE'
This is in the future, so it is accepted:
SQL> insert into your_table values (date '2021-12-26');
1 row created.
SQL>
As of
the current date comes up as an error when entered such as 12/12/2021 (today date)
Maybe you meant to say
IF( :new.date_time < trunc(sysdate))
which truncates sysdate to midnight today. In that case, today's date is also accepted:
SQL> CREATE OR REPLACE TRIGGER trg_chk_future
2 BEFORE INSERT ON your_table
3 FOR EACH ROW
4 BEGIN
5 IF( :new.date_time < trunc(sysdate))
6 THEN
7 RAISE_APPLICATION_ERROR( -20001, 'date_time must be in the future' );
8 END IF;
9 END;
10 /
Trigger created.
SQL> insert into your_table values (date '2021-12-12');
1 row created.
SQL>
I need to insert the date column record along with hour,min,sec, for example my joining date is 10/10/2021 but i need to insert 10/10/2021 08:05:25 i need output like this to get inserted
My insert query:
INSERT INTO lease_rent_receipts
(billing_start_date, billing_end_date,
charge_category, due_amount,
due_date, client_id,total_payable, description)
VALUES (l_billing_start_date,l_billing_end_date,l_charge_category, l_due_amount,
l_due_date, l_client_id,l_total_payable, l_description);
Main for due_date column i need to insert along with hrs:min:sec
kindly assist
To demonstrate my earlier comments. Notice on the final query of the table, I am querying the same column - the same data - with three different formats:
SQL> create table my_demo
2 (demo_date date)
3 ;
Table created.
SQL> declare
2 l_demo_date date := to_date('2021-10-22 12:21:43','yyyy-mm-dd hh24:mi:ss');
3 begin
4 insert into my_demo (demo_date)
5 values (l_demo_date)
6 ;
7 end;
8 /
PL/SQL procedure successfully completed.
SQL> select demo_date,
2 to_char(demo_date,'dd-Mon-yyyy') demo1,
3 to_char(demo_date,'yyyy-mm-dd hh24:mi:ss') demo2
4 from my_demo;
DEMO_DATE DEMO1 DEMO2
--------- -------------------- -------------------
22-OCT-21 22-Oct-2021 2021-10-22 12:21:43
1 row selected.
SQL> --
SQL> drop table my_demo purge;
Table dropped.
Use timestamp
to_timestamp(date_col, 'DD/MM/YYYY 24hh:mm:ss' )
DECLARE
l_billing_start_date lease_rent_receipts.billing_start_date%TYPE;
l_billing_end_date lease_rent_receipts.billing_end_date%TYPE;
l_charge_category lease_rent_receipts.charge_category%TYPE;
l_due_amount lease_rent_receipts.due_amount%TYPE;
l_due_date lease_rent_receipts.due_date%TYPE;
l_client_id lease_rent_receipts.client_id%TYPE;
l_total_payable lease_rent_receipts.total_payable%TYPE;
l_description lease_rent_receipts.description%TYPE;
BEGIN
-- Use a DATE literal and add an INTERVAL DAY TO SECOND literal.
billing_start_date := DATE '2021-10-10' + INTERVAL '08:05:25' HOUR TO SECOND;
-- or use a TIMESTAMP literal.
billing_start_date := TIMESTAMP '2021-10-10 08:05:25';
-- Or use TO_DATE.
billing_start_date := TO_DATE('10/10/2021 08:05:25', 'DD/MM/YYYY HH24:MI:SS');
-- Set other variables.
INSERT INTO lease_rent_receipts(
billing_start_date, billing_end_date, charge_category, due_amount,
due_date, client_id,total_payable, description
) VALUES (
l_billing_start_date, l_billing_end_date, l_charge_category, l_due_amount,
l_due_date, l_client_id,l_total_payable, l_description
);
END;
/
I'm trying to insert in a table the date and the time,but at the end only the date is insrted.
here's the code:
create table myDate(date_value Date PRIMARY KEY );
INSERT INTO myDate(date_value ) VALUES (to_date('14/09/2010 18:00','dd/mm/yyyy hh24:mi'));
And I get only 14/09/2010 stocked in the table myDate.What's the problem(is there a way to do that without timestamp)?
I think it worth noting that an alternatives to setting the session NLS parameter is the explicit use of the to_char function. I prefer the to_char because it leaves no doubt to anyone reading the code. Reliance on NLS can be iffy because it can be set at different levels. Besides, if you don't explicitly use to_char, oracle will still call it in the background, using the controlling setting of NLS_DATE_FORMAT.
SQL> -- create table
SQL> Create table mytest (dob date);
Table created.
Elapsed: 00:00:00.08
SQL> insert into mytest values (sysdate);
1 row created.
Elapsed: 00:00:00.03
SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
SQL> select dob nls_default,
2 to_char(dob,'dd-mm-yyyy') dob1,
3 to_char(dob,'yyyy-mm-dd') dob2,
4 to_char(dob,'dd-mm-yyyy hh24:mi:ss') dob3
5 from mytest;
NLS_DEFAU DOB1 DOB2 DOB3
--------- ---------- ---------- -------------------
11-DEC-20 11-12-2020 2020-12-11 11-12-2020 11:45:31
1 row selected.
Elapsed: 00:00:00.03
SQL> drop table mytest purge;
Table dropped.
For more on the subject, see this article.
Depending on the tool you are using is most likely a display issue.
you might want to try something like this
alter session set nls_date_format = 'DD-MON-YYYY HH12:MI:SS PM';
This will alter your sesssion to display the date with full timestamp.
I use oracle sql developer https://www.oracle.com/database/technologies/appdev/sqldeveloper-landing.html
If I don't set the date to my session while I'm writing a query I may see an unexpected date format.
Let us know if that is the case for you as well.
I am running a query on clocking data for my company. I have a query with 2 fields: CLOCK_IN1 and CLOCK_OUT1. When I run the query I see the proper CLOCK_IN1 but the CLOCK_OUT1 is being populated with a date near SYSDATE. CLOCK_OUT1 is NULL in the database and it's replacing the NULL with this date.
Is there a setting that populates a date when it's NULL?
There's either
a DEFAULT value applied to that column, or
a database trigger that does it.
This is how the first works:
SQL> create table test
2 (clock_in1 date,
3 clock_out1 date default sysdate
4 );
Table created.
SQL> insert into test (clock_in1) values (date '2020-08-23');
1 row created.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select sysdate from dual;
SYSDATE
-------------------
03.11.2020 20:23:03
SQL> select * from test;
CLOCK_IN1 CLOCK_OUT1
------------------- -------------------
23.08.2020 00:00:00 03.11.2020 20:22:48
SQL>
And this is the second:
SQL> drop table test;
Table dropped.
SQL> create table test
2 (clock_in1 date,
3 clock_out1 date
4 );
Table created.
SQL> create or replace trigger trg_bi_test
2 before insert on test
3 for each row
4 begin
5 :new.clock_out1 := nvl(:new.clock_out1, sysdate);
6 end;
7 /
Trigger created.
SQL> insert into test (clock_in1) values (date '2020-08-23');
1 row created.
SQL> select * from test;
CLOCK_IN1 CLOCK_OUT1
------------------- -------------------
23.08.2020 00:00:00 03.11.2020 20:24:23
SQL>
How to "fix" it?
SQL> alter table test modify clock_out1 default null;
Table altered.
SQL>
As of the trigger, well ... it depends on what it is doing, but - removing a line that sets column value would do.