I have the Data in the date formats of
2nd November 2010
15th Mar 2013 -- and so on.
I need to pick up these data and insert into the field of type DATE.
How can I achieve that?
select to_char(sysdate,'ddth Month YYYY','NLS_DATE_language=American') from dual
output:
19th November 2014
select to_date('15th Mar 2013','dd"th" Mon YYYY','NLS_DATE_language=American') from dual
used to trans varchar to date format.
Hope helps you.
You just need to cast the string to a date with the appropriate format mask:
insert into your_table values (
to_date('2nd November 2010', 'ddth Month YYYY')
)
The documentation has a complete list of format models. Find out more.
However, you have a problem because your input has different formats. We cannot use the same mask to match NOVEMBER and MAR; the second date requires a mask of 'ddth Mar YYYY'.
So you will need to write a function which catches ORA-01861: literal does not match format string and applies a different mask; depending on the quality of your input data you may need to have several of these. This situation is common with applications which don't use strong data-typing, and so demand data cleansing when they interact with more rigourous systems.
Related
I have a table (my table ) with a varchar2 column (my_column) , this column inculdes data that may be dates, in almost every known date format. like
dd/mm/yyyy
mm/dd/yyyy
ddMONyyyy
ddmmyyyyy
yymmdd
mm.dd.yy
dd/mm/yyyy hh:24:ss
mm-dd-yyyy
and so many .
Also it could contains a free text data that may be numbers or text.
I need the possible fastest way to retrieve it as a date , and if it's cannot match any date format to retrieve null
Said that this is really a bad and dangerous way to store dates, you could try with something like the following:
select myColumn,
coalesce(
to_date(myColumn default null on conversion error, 'dd/mm/yyyy' ),
to_date(myColumn default null on conversion error, 'yyyy mm dd' ),
... /* all the known formats */
to_date(myColumn default null on conversion error ) /* dangerous */
)
from myTable
Here I would list all the possiblly expected formats, in the right order and trying to avoid the to_date without format mask, which can be really dangerous and give you unexpected results.
The simple answer is: You cannot convert the strings to dates.
You say that possible formats include 'dd/mm/yyyy' and 'mm/dd/yyyy'. So what date would '01/02/2000' be? February 1 or January 2? You cannot know this, so a conversion is impossible.
Having said that, you may want to write a stored procedure where you parse the text yourself and only convert unambiguous strings.
E.g.: Is there a substring containing colons? Then this may be the time part. In the rest of the string: Is there a four-digit number? Then this may be the year. And so on until you are either 100% sure what date/time this is or you cannot unambiguously determine the date (in which case you want to return null).
Example: '13/01/21' looks very much like January 13, 2021. Or do you allow the year 2013 in your table or even 2001 or even 1921 or ...? If you know there can be no year less then, say, 2019 in the table and no year greater than 2021, then the year must be 2021. 13 cannot be the month, so it must be the day, which leaves 01 for the month. If you cannot rule out all other options, then you would have to return null.
I need help to change the date format from (05 May 2016 12:00 AM) to (YYYY-MM-DD HH:MM:SS) format.
Can you please help me on this?
Many thanks for your help.
I have tried below format
SELECT TO_CHAR(TO_DATE('2 Apr 2015 12:00 AM', 'DD-MON-YYYY '), 'YYYY-MM-DD')
FROM dual;
Thanks for the Help MTO. But i am using same format in sqlldr then getting below error.
ora-01821 date format not recognized
LAST_UPDATE DATE 'TO_CHAR(TO_DATE(:LAST_UPDATE, 'DD MON YYYY HH12:MI AM'),'YYYY-MM-DD HH24:MI:SS')',
Use the full format mask:
SELECT TO_CHAR(
TO_DATE( '2 Apr 2015 12:00 AM', 'DD MON YYYY HH12:MI AM'),
'YYYY-MM-DD HH24:MI:SS'
)
FROM dual;
If you're doing this in SQL*Loader and populating a DATE column then you want your initial string to be converted to a date, not back to another string in another format.
If you use the SQL operator functionality then you only need the inner to_date() part, not the outer to_char(), and notice that the operator is enclosed in double quotes rather than single quotes:
LAST_UPDATE "TO_DATE(:LAST_UPDATE, 'DD MON YYYY HH12:MI AM')",
But there is simpler handling for datetimes and intervals, which you are sort of trying to use with the DATE keyword; but then you're supplying the SQL operators instead of just a format mask. You can just do:
LAST_UPDATE DATE 'DD MON YYYY HH12:MI AM'.
This assumes SQL*Loader is run in an english-language NLS_LANG environment, since it relies on the NLS_DATE_LANGUAGE setting to handle the MON element. If that is not the case then the SQL operator approach can be used, with the optional third argument to to_date() to specify that it is expecting the string to be in English.
Your question seems to be partly confused by thinking that Oracle stores dates with a specific format. It does not; it uses an internal representation which you generally don't need to know about, and it's up to your client to display that internal value in a readable format, which is does using explicit or implicit conversions. You seem to be assuming dates are 'stored' as YYYY-MM-DD HH24:MI:SS, but that is just how your client is displaying the data to you.
1) Why is that this doesn't works
select * from table where trunc(field1)=to_date('25-AUG-15','DD-MON-YY');
select * from table where trunc(field1)=to_date('25/Aug/15','DD/MON/YY');
row is returned in above cases.
So, does this mean that no matter what format the date is there in field1, if it is the valid date and matches with 25th August, it will be returned ( it won't care what format specifier we specify at the right side of the query i.e. DD-MON-YY or DD/MON/YY or anything else) ?
2) but comparsion as string exactly works:
select * from table where to_char(field1)=to_char(to_date
('25/AUG/15','DD/MON/YY'), 'DD/MON/YY');
no row is returned as the comparison is performed exactly.
I have field1 as '25-AUG-15' ( although it can be viewed differently doing alter session NLS_DATE_FORMAT...)
field1 is of DATE type
Any help in understanding this is appreciated specifically with respect to point 1
The DATE data type does not have format -- it's simply a number. So, a DATE 25-Aug-2015 is the same as DATE 25/AUG/15, as well as DATE 2015-08-15, because it's the same DATE.
Strings, on the other hand, are collections of characters, so '25-Aug-2015' is obviously different from '25/AUG/15'.
In the first example you are comparing DATE values. In the second example you are comparing strings.
So you have a field of type DATE with value of The 25th of August 2015,
but it could be visualized in different ways, what in fact is named format.
The DATE has format!
The DATE has implicit format defined by Oracle, in your case it is DD-MON-YY, because you see your field as 25-AUG-15.
You can select your data without TO_DATE conversion, just matching this default format like this:
select * from table where trunc(field1)='25-AUG-15';
In fact, it's not recommended, because if someone will change the default format, Oracle will not be able to understand that you are going to tell him a DATE.
So the to_date conversion in this case:
select * from table where
trunc(field1)=to_date('25/AUG/15','DD/MON/YY');
is used to specify that you wanna tell to Oracle a DATE type with value of 25th of August 2015, using a diffrent format, specified as second parameter. (DD/MM/YY in this case).
I have a column in my table which will store the time as hh24miss format, i.e it stores as 091315 which is 09 hrs 13 min 15 sec. I need to convert it into HH24:MI:SS AND concatenate it with the date column which is in YYYYMMDD format.
Simply, the following columns Date: 19940601 and Time: 091315 need to be converted to
01-Jan-94 09:13:15.
You should not store dates as strings, and there is no need to store the time in a separate field. Oracle's DATE data type includes times down the to the second. (You'd need TIMESTAMP for fractions of a second).
If you are really stuck with this schema then you need to convert the two strings into a DATE:
to_date(date_column || time_column, 'YYYYMMDDHH24MISS')
You can then display that in whatever format you want; what you showed would be:
to_char(to_date(date_column || time_column, 'YYYYMMDDHH24MISS'),
'DD-Mon-RR HH24:MI:SS')
Although the data you have is June, not January.
SQL Fiddle demo.
But really, please revisit your schema and use the appropriate data type for this, don't store the values as strings. You have no validation and no easy way to check that the values you have stored actually represent valid dates and times.
A client site has supplied the following extract file for us to load into our database.
The problem is, for certain rows (the second row for example) the CREATED_DATE and the LAST_UPDATE_DATE are in "dd Mmm YYYY..." date format when the rest the rows (such as the top) are in the format of "YYYY-MM-DD HH24.MI.SSXFF"
PRIMARY_ID ID VALUE CREATED_DATE LAST_UPDATE_DATE
20166267 20834830491 2012-04-30 08:18:00 2012-04-30 08:18:00
20166536 9112 01 Oct 2010 17:27:04 01 Oct 2010 17:27:04
My questions are:
Q1. To avoid having to request an extract, can we manipulate these “dd Mmm YYYY...” formatted dates at import time in SQL Loader using the .ctl script? CUrrently my .ctl is
My .ctl file is scripted to import using:
IDENTIFIER_START_DATE TIMESTAMP "YYYY-MM-DD HH24.MI.SSXFF",
LAST_UPDATE_DATE TIMESTAMP "YYYY-MM-DD HH24.MI.SSXFF"
Q2. Is simply asking them for a re-extract with all date formats as requested the best practice in situations like this?
Whether to request a re-extract of the data depends on a number of factors.
Is this a one-time process or an ongoing data feed? It may be perfectly reasonable to try to do your best with a one-time load of data where it is easier to eyeball the outliers. If you are going to manage an ongoing data feed, it generally makes much more sense to agree on a strict standard for the file rather than trying to manually inspect problematic rows.
Does the client have an incentive to make your load process simple and repeatable? Or was the client sold on a fixed price to load the data in whatever format they want to provide it? If the client has an incentive to make the load process simple and repeatable, it makes sense for them to invest the time to generate a clean file. If you've sold them a fixed price for whatever work needs to be done to turn the file into coherent data, on the other hand, they probably won't be pleased if you push a lot of that work back on them.
Are there rows where the data is ambiguous? For example "01-02-03" could refer to Jan 2, 2003 or Jan 2, 1903 or Feb 3, 2001 or a number of other dates. If there is ambiguity, it makes sense to request a re-extract.
As to how to load the data, while it is possible to do this in a single step, you generally wouldn't want to. It would generally make more sense to load the data into a staging table (or use an external table) where all the columns are declared as VARCHAR2 and then write some ETL logic that transforms the data into the appropriate data types (and logs errors for the data that cannot be converted). For example, if you loaded the data into a staging table where all the columns were defined as VARCHAR2, you could use something like the my_to_date function in this thread to try a number of different format masks to find one that works (if there are a lot of possible masks, you may want to iterate through a collection rather than hard-coding the two masks as I did in that example).
One additional point... An Oracle DATE stores the time to the second which appears to be the precision of the data you're being given. It would, therefore, seem to make more sense to load the data into a DATE column rather than a TIMESTAMP column.
Use this .ctl script:
load data
append
into table schema_name.table_name
fields terminated by ';' optionally enclosed by '"'
(
PRIMARY_ID,
ID_VALUE,
CREATED_DATE "to_date(:CREATED_DATE, case when regexp_substr(:CREATED_DATE,'\w+',1,2)=regexp_substr(:CREATED_DATE,'\d+',1,2) then 'YYYY-MM-DD HH24:MI:SS' else 'dd Mon YYYY HH24:MI:SS' end)",
LAST_UPDATE_DATE "to_date(:LAST_UPDATE_DATE, case when regexp_substr(:LAST_UPDATE_DATE,'\w+',1,2)=regexp_substr(:LAST_UPDATE_DATE,'\d+',1,2) then 'YYYY-MM-DD HH24:MI:SS' else 'dd Mon YYYY HH24:MI:SS' end)"
)