Working with dates in PL SQL - 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

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')

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>

how to get the date format in 'DD-MM-YY' format in ORACLE without using TO_CHAR?

How do we convert a date in the 'DD-MM-YY' format WITHOUT using to_char ?
If I use the following query i get it in DD-Mon-YY format ?
select TO_DATE(SYSDATE,'DD-MM-YY') from dual ;
Output : 29-Mar-18
I want it in 29-03-18 format , without using to_char.
Is it possible ?
How do we convert a date in the 'DD-MM-YY' format WITHOUT using to_char ?
This is a common misconception that dates in the database have a format.
A date does not have a format - it is stored internally to the database as 7-bytes (representing year, month, day, hour, minute and second) and it is not until whatever user interface you are using (i.e. SQL/Plus, SQL Developer, Java, etc) tries to display it to you, the user, and converts it into something you would find meaningful (usually a string) that the date is given a format so that you, the user, find it meaningful on the client software.
So the question you should be asking is:
How do we get <insert name of SQL client software here> to change the default format it uses for a DATE data type?
If you are using SQL/Plus or SQL Developer then it will use the NLS_DATE_FORMAT session parameter to format the date. You can change this using:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MM-YY';
Note: This is a session parameter and will only change the format for the current session (not for any other users or any subsequent sessions).
If you want to set this as the session default then you could set a logon trigger (if users are relying on the previous default format then applying this may not be well received).
You can also change the preferences in the SQL Developer GUI as described here.
we dont have alter permission , its client db
Then use TO_CHAR( date, format_model ) - that is what it is there for.
Note: Please do not use 2-digit years as the expected format. It is a source of errors when dates are given an unexpected and wrong century.
If I use the following query i get it in DD-Mon-YY format ?
select TO_DATE(SYSDATE,'DD-MM-YY') from dual ;
TO_DATE( date_string, format_model ) takes two string arguments and Oracle will implicitly call TO_CHAR to convert your date to a string so it will match the expected data type and then when the client program formats it it will implicitly perform a similar transformation again. So your query is effectively:
SELECT TO_CHAR(
TO_DATE(
TO_CHAR(
SYSDATE,
( SELECT VALUE
FROM NLS_SESSION_PARAMETERS
WHERE PARAMETER = 'NLS_DATE_FORMAT'
)
),
'DD-MM-YY'
),
( SELECT VALUE
FROM NLS_SESSION_PARAMETERS
WHERE PARAMETER = 'NLS_DATE_FORMAT'
)
)
FROM DUAL;
If the NLS_DATE_FORMAT is MM-DD-YY then SYSDATE will be implicitly converted to the default MM-DD-YY format then explicitly converted to a date using your format DD-MM-YY, and the day/month values will be swapped, before being converted back to the default MM-DD-YY format for display. Relying on implicit conversions is prone to many errors - try to avoid it.
If you want a date for your SQL client to format using their default format then just use:
SELECT SYSDATE FROM DUAL;
If you want to get a formatted date then use TO_CHAR( date, format_model ):
SELECT TO_CHAR( SYSDATE, 'DD-MM-YY' ) FROM DUAL;
ALTER SESSION is one option:
SQL> alter session set nls_date_format = 'dd-mm-yy';
Session altered.
SQL> select sysdate from dual;
SYSDATE
--------
29-03-18
Note that what you did - applied TO_DATE function to SYSDATE - is wrong. SYSDATE already returns DATE, so you could have applied TO_CHAR to it (with appropriate format mask), but not TO_DATE.
I would suggest you to use TO_CHAR or nls_date_format , though EXTRACT is an alternative if you want to answer an interview question.
SELECT EXTRACT (DAY FROM SYSDATE)
||'-'
|| LPAD(EXTRACT (MONTH FROM SYSDATE), 2, 0)
|| '-'
|| SUBSTR( EXTRACT(YEAR FROM SYSDATE),-2) as dt
FROM DUAL;

ORA-01843: not a valid month with data type conversion

I have created a view where one of column command is:
TO_CHAR( TO_DATE(sysdate ||' '||TIMING.TIME,'dd-MON-RRRR HH:MIAM'),'dd-MON-RRRR HH:MIAM') as time
The value of TIMING.TIME is like this: 09:30AM as varchar2
When I run the query: select TO_DATE(time,'DD-MON-RRRR HH:MIAM')from view
I get the error
ORA-01843: not a valid month
NLS Language is American.
TO_DATE(sysdate
That is wrong.
Never apply TO_DATE on DATE data type. It forces Oracle to:
first convert it into a string
then convert it back to date
based on the locale-specific NLS settings. You need TO_DATE to convert a literal into date. For date-arithmetic, leave the date as it is.
If you are trying to configure the time portion in current date, then:
1. First convert the date into string
2. Then concatenate the time portion to the string
3. Finally apply TO_DATE
For example,
SQL> alter session set nls_date_format='DD-MM-YYYY HH:MI:SS AM';
Session altered.
SQL> SELECT to_date(TO_CHAR(sysdate, 'mm/dd/yyyy')
2 ||' '
3 ||'09:30AM', 'mm/dd/yyyy hh:miAM') TIME
4 FROM dual;
TIME
----------------------
14-10-2015 09:30:00 AM
Remember,
TO_DATE is used to convert a string into date.
TO_CHAR is used to display the date in desired string format.
Modified query for you:
to_date(TO_CHAR(sysdate, 'mm/dd/yyyy') ||' ' ||TIMING.TIME, 'mm/dd/yyyy hh:miAM')
AS "TIME"
sysdate stores time and it would be better to convert it to char before concatenation
TO_CHAR(sysdate,'dd-MON-RRRR')||' '||TIMING.TIME

store dates in oracle

I have a table as
create table Dummy (date_created date)
in oracle.I want to store date in 'dd-mon-yyyy' (12-dec-2010) format.
How should i do this.
Please help.
In Oracle a column created with the DATE datatype just stores the date. It doesn't have a particular format, it just stores the day, month, year, hour, minute, and second. You need to convert from whatever format you have using the TO_DATE function. If you have a text string with the date in 'dd-mon-yyyy' format and you want to put this date into your table you'd use something like
INSERT INTO DUMMY (DATE_CREATED)
VALUES (TO_DATE('01-FEB-2011', 'DD-MON-YYYY');
Going the other way (from DATE column value to character string) you'd use the TO_CHAR function. If you were retrieving a value from your table and wanted to convert it to 'DD-MON-YYYY' format you'd use something like
SELECT TO_CHAR(DATE_CREATED, 'DD-MON-YYYY')
FROM DUMMY;
Share and enjoy.
Use to_date() function. In your case, the syntax would be
insert into Dummy values (to_date('08-09-2010', 'dd-mm-yyyy'));
Here is a link to the detailed help.
The DATE datatype will store date and time information (century, year, month, day, hours, minutes, and seconds) in an internal format in the database. When you get it out of the database, you can choose to display it in whatever format you like.
This information is either created using implicit conversion from a string or explicitly using either the TO_DATE function or the ANSI date literal. If you look in the v$nls_parameters view, this will tell you what the NLS_DATE_FORMAT is which is generally used for the implicit conversion. This may often be defined as DD-MON-RR, which might be why the date will come out as 23-DEC-10 when the query select sysdate from dual is run. (Not entirely sure I'm right about the nls stuff. Correct me if I'm wrong.)
However, all the date information is available if you know how to get it. The query select to_char(sysdate, 'dd-mon-yyyy hh24:mi:ss') from dual will return all the date fields.
Likewise, the insert statement shown below will create a row with a date value in it.
insert into dummy (date_created)
values (to_date('12-dec-2010 12:34:56', 'dd-mon-yyyy hh24:mi:ss'))`
This data can then be retrieved.
select date_created from dummy
This will implicitly convert the date to a character string using the NLS_DATE_FORMAT, providing the output below.
DATE_CREA
---------
23-DEC-10
The full date information is available by explicitly converting the date to a character string.
select to_char(date_created, 'DD-MON-YYYY') as date_created from dummy;
select to_char(date_created, 'DD-MON-YYYY HH24:MI:SS') as date_created
from dummy;
This will provide output in the format you require:
DATE_CREATE
-----------
23-DEC-2010
If you always use the TO_DATE and TO_CHAR functions to convert to/from a date datatype, then you will have fewer problems. Implicit conversion is useful but can cause some confusion or problems.
You can keep and eye here
http://www.techonthenet.com/oracle/functions/to_date.php
use to_date function to save a data with the format you need. I suggest to use SYSDATE updating table and when you need to read data from table use something like that:
dbms_output.put_line(TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS'));
to solve your problem use:
to_date('08/JAN/2010', 'DD/MON/YYYY')
Just use TRUNC(YourDate) if date have time part, it will be truncate time part. Oracle have not just 'DATE' type, 'DATE' always have time part.
However if you do not specify time - it will 00:00:00.
SELECT TRUNC(SYSDATE) from dual
Result:
23-12-2010
Oracle does not support DATE without time part.
You can make it always be an integer date by adding a CHECK constraint:
CREATE TABLE dummy (date_created date CHECK (date_created = TRUNC(date_created)))
, insert it in any format you want:
INSERT
INTO dummy (date_created)
VALUES (TO_DATE('23-DEC-2010', 'dd-mon-yyyy'))
and select it in any format you want:
SELECT TO_CHAR(date_created, 'dd-mon-yyyy')
FROM dummy