Appending the HH:MI:SS to to_date function - sql

I have a table in DB from which I take values from a date field.I store this date value in a cursor. currently the date value is of the format DD:MON:YY. Now I convert this date into character using to_char function so as to append time 00:00:00 to it. now I tried converting back to the date format , but the timestamp is not appended and the date format is not as I have given( format is same as that of the date field in DB).but the to_char function returns the correct format as I have given.
Some of the code snippets are as follows:
Initialized a cursor as
cursor cur is
select to_char(STV_FROM_DATE,'DD:MON:YYYY:')STV_FROM_DATE :---from a table in DB
cur1 cur%rowtype;
begin
open cur;
loop
fetch cur into cur1;
dbms_output.put_line(cur_1.STV_FROM_DATE);
This is giving the value correctly as:
01:JAN:2000:
01:JAN:2000:
01:JAN:2000:
01:JAN:2000:
Now I appended the timestamp 00:00:00 to this and did the to_date operation as follows:
STV_FROM_DATE_BC := cur_1.STV_FROM_DATE;
STV_FROM_DATEBCKUP:=to_date(STV_FROM_DATE_BC,'DD:MM:YY:HH24:MI:SS');
dbms_output.put_line(STV_FROM_DATEBCKUP);
The result obtained is:
01-JAN-00
01-JAN-00
01-JAN-00
Could anyone help me to solve this issue and convert the timestamp appended character to date?

DBMS_OUTPUT is to DISPLAY. so, to display a DATE, you need TO_CHAR.
STV_FROM_DATEBCKUP:=to_date(STV_FROM_DATE_BC,'DD:MM:YY:HH24:MI:SS');
dbms_output.put_line(STV_FROM_DATEBCKUP);
Never use YY, always mention 4 digits YYYY for the complete year. You don't want to introduce the Y2K bug again. Above, you are trying to display the date value, but you did not mention the format model that you want to display. So simply use TO_CHAR along with proper format model.
Reason Without providing a proper format model, your client would just display according to your locale-specific NLS settings. For example, if I just display the sysdate, I would see the format that is mentioned in my NLS_DATE_FORMAT in v$parameters.
SQL> select parameter, value from v$nls_parameters where parameter='NLS_DATE_FORMAT';
PARAMETER VALUE
-------------------- --------------------
NLS_DATE_FORMAT DD-MON-RR
SQL> select sysdate from dual;
SYSDATE
---------
27-JAN-15
SQL>
So, I got 27-JAN-15 as SYSDATE, since my NLS_DATE_FORMAT is DD-MON-RR. You could set it at system level or at session level.
SQL> alter session set NLS_DATE_FORMAT='DD:MM:YYYY:HH24:MI:SS';
Session altered.
SQL> select sysdate from dual;
SYSDATE
-------------------
27:01:2015:11:54:07
SQL>
So, you could either set your NLS_DATE_FORMAT to set the format model that suits you. Let's see a test case -
SQL> set serveroutput on
SQL> DECLARE
2 STV_FROM_DATE_BC VARCHAR2(20);
3 STV_FROM_DATEBCKUP DATE;
4 BEGIN
5 STV_FROM_DATEBCKUP:= NULL;
6 STV_FROM_DATE_BC :='01:JAN:2000:';
7 STV_FROM_DATE_BC :=STV_FROM_DATE_BC||'00:00:00';
8 dbms_output.put_line('Input date literal = '||STV_FROM_DATE_BC);
9 STV_FROM_DATEBCKUP:=to_date(STV_FROM_DATE_BC,'DD:MON:YYYY:HH24:MI:SS');
10 dbms_output.put_line('Date without format model = '||STV_FROM_DATEBCKUP);
11 dbms_output.put_line('Date with proper format model = '||TO_CHAR(STV_FROM_DATEBCKUP,'DD:MM:YYYY:HH24:MI:SS'));
12 END;
13 /
Input date literal = 01:JAN:2000:00:00:00
Date without format model = 01-JAN-00
Date with proper format model = 01:01:2000:00:00:00
PL/SQL procedure successfully completed.
SQL>

Related

Oracle regexp to validate time

I am trying to validate a regular expression in oracle SQL to check Time format:
The desired format I want to check is:
2/27/2020 3:53:02 PM
I have already created a regexp for a date format such as:
20200227 --> using REGEXP_LIKE('20190222', '^\d{4}(0[1-9]|(1[0-2]))(0[1-9]|[1-2][0-9]|3[0-1])$')
Could someone give me a hint for the time format?
To me, it looks as if you started it wrong. If you want to validate date (time) format, you're storing it as a string, which is a big mistake.
If you set that column (or whatever it is) as DATE, which - in Oracle - contains both date and time, then database will take care that you can enter only valid values.
Format you mentioned, or any other, is matter of display, not storage.
One option is to force TO_DATE conversion; something like this:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> set ver off
SQL> select to_date('&date_value', 'mm/dd/yyyy hh:mi:ss am') result from dual;
Enter value for date_value: 2/27/2020 3:53:02 pm
RESULT
-------------------
27.02.2020 15:53:02
SQL> /
Enter value for date_value: 13/54/2020 x:23:83 am
select to_date('13/54/2020 x:23:83 am', 'mm/dd/yyyy hh:mi:ss am') result from dual
*
ERROR at line 1:
ORA-01843: not a valid month
SQL>
So: if conversion works, then format is OK. Otherwise, you entered something stupid and conversion won't pass. Such a code can be used as a function which returns e.g. Boolean.
Don't use a regular expression as the edge cases will make the expression long and complicated (i.e. months can have 28-31 days, leap years every 4 years ... except for multiples of 100 ... except for multiples of 400).
For example, your date regular expression ^\d{4}(0[1-9]|(1[0-2]))(0[1-9]|[1-2][0-9]|3[0-1])$ would validate 20190229 or 20200230 or 20200931 neither of which are valid dates.
A time regular expression is easier as you only have hours 0-23, minutes 0-59, seconds 0-59 (assuming you are ignoring leap seconds) and possibly fractional seconds and would be:
([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?
However, a simpler way is just to try to perform a conversion to a DATE and if it fails then you know it isn't valid. If you are on Oracle 12.2 or later then you can use the built-in VALIDATE_CONVERSION function:
SELECT validate_conversion( '20200230000000' AS DATE, 'YYYYMMDDHH24MISS' )
FROM DUAL
If you are on an earlier version then you can create a custom function to try and perform the conversion and if an exception occurs then you know the input is invalid:
CREATE FUNCTION isValidDate(
date_string IN VARCHAR2,
format_model IN VARCHAR2 DEFAULT 'FXYYYYMMDDHH24MISS'
) RETURN NUMBER
IS
d DATE;
BEGIN
d := TO_DATE( date_string, format_model );
RETURN 1;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
/
While looking into string Regex, I found that this one does the job that I'm looking for:
REGEXP_LIKE('2/27/2020 3:53:02 PM','^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}:\d{1,2}:\d{1,2} [AP]M\z')

literal does not match format string-version 11

In my SQL query I have,
TO_DATE('2019-07-22' , 'YYYY-MM-DD')
I want to pass sysdate-1 instead of hard coding the date value.
I tried this,
select TO_CHAR(to_date(
sysdate-1,'DD-Mon-YY'),'YYYY-MM-DD')dates from dual
and replaced the same in the SQL query but am getting the below error,
ORA-01861: literal does not match format string
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.
Sysdate is a function that returns DATE datatype; you don't TO_DATE it. Therefore:
SQL> select to_char(sysdate - 1, 'yyyy-mm-dd') result from dual;
RESULT
----------
2019-08-01
SQL>
If you meant to use date datatype, then - as comments suggest - there's no need for any TO_something function:
SQL> select sysdate as today,
2 sysdate - 1 as yesterday
3 from dual;
TODAY YESTERDA
-------- --------
02.08.19 01.08.19
SQL>
The result of such a subtraction is date datatype. The way it is presented to you depends on NLS settings; in my database, it is set to dd.mm.yy. In order to present it differently, you'd either modify settings or apply to_char with appropriate format mask, e.g.
SQL> alter session set nls_date_format = 'yyyy-mm-dd';
Session altered.
SQL> select sysdate as today,
2 sysdate - 1 as yesterday
3 from dual;
TODAY YESTERDAY
---------- ----------
2019-08-02 2019-08-01
SQL>
Although sysdate is a date data type, Oracle still stores a time component.
Your code (attempts to) remove the time component. For this, use trunc():
select trunc(sydate - 1)
or
select trunc(sysdate - interval '1' day)
Note that the time component is often now shown when you select the data and look at it.

Converting timestamp to date in Oracle 12c

I want to convert a given timestamp in such format: 2019-04-08 00:00:00.0 to a date in this format: 2019-04-08.
I have already tried using:
SELECT TO_DATE('2019-04-20 00:00:00.0','YYYY-MM-DD') from dual;
But I got prompted with:
ORA-01830: date format picture ends before converting entire input
string
I think you may have some conceptual misunderstanding about how the TO_DATE function works, and also about how dates are processed by the DBMS.
YYY-MM-DD does not match the format of the actual string you're importing (2019-04-20 00:00:00.0) That's what the error is telling you. You must tell the TO_DATE function what to expect in the date string you input into it. You do that by means of the format string. if you don't specify a format string which matches the format you're actually going to supply, then the function will fail to process the string.
Next, you say you want to convert it "to a date in this format"...but this does not entirely make sense. TO_DATE converts a string into a variable of type DATETIME - i.e. a date object. A date object does not not exist in any particular format, it exists as an object. Internally it will store the date information in a way which is independent of any human-readable date format. The format relates entirely to the presentation of the date when seen as a string. Once you have a date object, you can then output the date in a particular format if you want to a human to be able to read it in the style that their culture is familiar with.
So, firstly to import your date string correctly as a date object, you can use an accurate format string, an also use TO_TIMESTAMP instead of TO_DATE so that it captures the sub-seconds value:
SELECT TO_TIMESTAMP('2019-04-20 00:00:00.0','YYYY-MM-DD HH24:MI:SS.FF5') from dual;
If you run this in a console the SELECT will then automatically re-format that date object (the result of the TO_DATE function) into the default date format configured in your server / session.
However if you actually want to see it on screen in a particular format, you can explicitly say so - a sensible way is using the TO_CHAR function:
SELECT TO_CHAR(TO_TIMESTAMPT('2019-04-20 00:00:00.0','YYYY-MM-DD HH24:MI:SS.FF5'), 'YYYY-MM-DD') from dual;
The full list of format specifiers can be found here (and in other places online as well).
Live demo of the above here: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=619d918ea73953e11b3150c6b560112c
Assuming the input is actual text, and not a real timestamp, you could try just truncating the text before you call TO_DATE:
WITH cte AS (
SELECT '2019-04-20 00:00:00.0' AS ts FROM dual
)
SELECT TO_DATE(SUBSTR(ts, 1, 10), 'YYYY-MM-DD')
FROM cte;
If your input is an actual Oracle timestamp, and you want to convert it to a date, then you may use CAST:
SELECT CAST(ts AS DATE) dt
FROM cte;
Would CAST do any good?
I'm setting date format so that it displays time component, although it is 00:00:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select cast(timestamp '2019-04-20 00:00:00.0' as date) result from dual;
RESULT
-------------------
20.04.2019 00:00:00
Another format (without time component):
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> select cast(timestamp '2019-04-20 00:00:00.0' as date) result from dual;
RESULT
----------
20.04.2019
SQL>
Or, using TO_CHAR function (so that session's date format doesn't matter):
SQL> select to_char(timestamp '2019-04-20 00:00:00.0', 'dd.mm.yyyy') result from dual;
RESULT
----------
20.04.2019
SQL>

Working with dates in PL SQL

I have a simple PL SQL code. However it is failing at date level. The date column is CODT. I declared CODT as date. And in database level, it is date with format YYYY-MM-DD.
I also tried alter session set nls_date_format = 'YYYY-MM-DD'; But it is throwing error.
The error message is ORA-01830: date format picture ends before converting entire input string
00000 - "date format picture ends before converting entire input string"
Could you let me know where I need to change it to date format/ where I am making a mistake ?
DECLARE
RID VARCHAR2(100);
KY VARCHAR2(200);
CODT DATE;
CURSOR FETCH_DTLS IS
SELECT ROW_ID,
KEY,
CUT_OFF_DT,
FROM TMP1
WHERE RN = 1;
BEGIN
OPEN FETCH_DTLS;
LOOP
FETCH FETCH_DTLS
INTO RID,
KY,
CODT;
EXIT WHEN FETCH_DTLS%NOTFOUND;
INSERT INTO tmp2
VALUES
(RID,
KY,
CODT
);
END LOOP;
COMMIT;
CLOSE FETCH_DTLS;
COMMIT;
END;
if you have date column which defined varchar2 in db you should use it like this:to_date(your_column/*CUT_OFF_DT*/, 'yyyy-mm-dd')
when you use VARCHAR2 field and insert it in a table with DATE data-type, then you tell oracle to: Cast VARCHAR2 to DATE
So your mistake is casting without providing any format, here are some date format examples used in oracle:
'YYYY-MM-DD'
'YYYY-MM-DD HH24:MI:SS'
there is also another function in oracle called TO_DATE which will do the job, it simply casts the string(char or varchar) to date with provided date-format and also provided calendar! Here is some examples:
TO_DATE('2016-12-15','YYYY-MM-DD')--uses default calendar of session
TO_DATE('2016-12-15','YYYY-MM-DD', 'nls_calendar=gregorian')
TO_DATE('1395-09-25','YYYY-MM-DD', 'nls_calendar=persian')--Solar base date used in IRAN
and reverse function is TO_CHAR
TO_CHAR(SYSDATE,'YYYY-MM-DD')--SYSDATE is in Date type so this works
there is another data-type related to dates, which is called TIMESTAMP
TO_CHAR(SYSTIMESTAMP,'YYYY-MM-DD HH24:MI:SSxFF')--SYSTIMESTAMP is in TIMESTAMP type so this works
finally we can use INTERVAL type to calculate interval between 2 dates(Specially timestamps) and there is a useful function called numtodsinterval which converts numbers to intervals, you can use it like this:
SYSDATE+NUMTODSINTERVAL(1,'Minute')
and this is an example:
SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS'),
TO_CHAR(SYSDATE+NUMTODSINTERVAL(1,'Minute'),'YYYY-MM-DD HH24:MI:SS')
FROM DUAL
which outputs:
1 2016-12-15 15:05:10 2016-12-15 15:06:10
I hope it will be useful in your future usages of DATE, goodluck

Perl and Oracle DB - help

I am using Oracle express database, and I would like to know how can I change the date formatting-
from dd-mm-yyyy to dd-mm-yyyy hh-mm. Also, I've heard something about alter session, but I don't know how to use it in Perl.
This is what I did so far:
my $sth = $dbh->prepare("INSERT INTO Perl
(A_FIELD,B_FIELD,C_FIELD,TIME_STAME)
VALUES
(?,?,?,TO_DATE(?,'DD/MM/YYYY HH24:MI'))");
Date fields in Oracle are not formatted for display - it's an internal format that you convert to/from on input/output. When you store a date in Oracle date datatype columns, you convert your character string to internal format by describing the date-time to the TO_DATE function with the format model string. Oracle interprets the character string to it's internal format. When you need to display the date, you do the reverse - you tell oracle how to display the date by again giving a format model, this time to the TO_CHAR function.
To illustrate with your example, you could convert dd-mm-yyyy to dd-mm-yyyy hh-mm without ever storing the value (I assume you meant to display hours-minutes. The format model for minutes is 'MI', since 'MM' is month):
SQL> SELECT TO_CHAR(TO_DATE('01-01-2020','DD-MM-YYYY'),'DD-MM-YYYY HH-MI') mydate
FROM DUAL;
MYDATE
----------------
01-01-2020 12-00
Note that with your example, the time portion of your date is not supplied on input, so it defaults to midnight. To store a time value in your date column, you must supply a time value in your input:
SQL> SELECT TO_CHAR(TO_DATE('01/01/2020 10:13','DD/MM/YYYY HH:MI'),'DD-MM-YYYY HH-MI') mydate
FROM DUAL;
MYDATE
----------------
01-01-2020 10-13
SQL>
Depending on what you're trying to do, the system date in Oracle can be obtained by a reference to the pseudo-column SYSDATE:
SQL> SELECT TO_CHAR(sysdate,'MM/DD/YYYY HH:MI:SS AM') dt1,
2 TO_CHAR(sysdate,'DD-MON-YYYY HH24:MI:SS') dt2
3 FROM dual;
DT1 DT2
---------------------- -----------------------------
07/01/2011 03:44:30 PM 01-JUL-2011 15:44:30
SQL>
So the roundabout answer to your question is that it entirely depends on what format your input date string is in. You convert that to Oracle's date type via a format model and the TO_DATE function, then convert the date item to a display format of your choosing via TO_CHAR and a format model. As for the "ALTER SESSION" command you alluded to in your question, you can specify a default format model for date conversions by specifying the NLS_DATE_FORMAT parameter in the ALTER SESSION command:
SQL> SELECT sysdate FROM dual;
SYSDATE
---------
02-JUL-11
SQL> ALTER SESSION SET nls_date_format='dd-mon-yyyy hh24:mi:ss';
Session altered.
SQL> SELECT sysdate FROM dual;
SYSDATE
--------------------
02-jul-2011 10:39:24
If the incoming date string is in mm-yyyy format, then you can use the statement below(TO_DATE(?,'MM-YYYY')) to convert the string to date:
$sth = $dbh->prepare("INSERT INTO Perl (A_FIELD,B_FIELD,C_FIELD,TIME_STAME) VALUES (?,?,?,TO_DATE(?,'MM-YYYY'))");