Convert String to Date field for SQL Oracle - oracle

I need to convert a string to a date field. The field stores 30 characters. Dates, when present, are formatted as 'yyyymmdd' (20170202). In all cases, dates have 22 spaces after. I need to format this field as a date field like this: dd-mm-yyyy.
I've tried several formulas:
TO_CHAR(PERSACTION.NEW_VALUE_02, 'dd-mm-yyyy') ,TO_CHAR(PERSACTION.NEW_VALUE_02, 'yyyymmdd'), trim(TO_CHAR(PERSACTION.NEW_VALUE_02, 'yyyymmdd')) with error message: invalid number format model. Your expertise is welcome and appreciated.

to_char(to_date( rtrim(new_value_02), 'yyyymmdd'), 'dd-mm-yyyy')
Should do the trick. rtrim removes spaces on right side of string. Then I convert it to date using the date format specified, and then convert it to a string again in the desired format.

Did tried to convert to date format and then to char again?
TO_CHAR(TO_DATE(PERSACTION.NEW_VALUE_02,'yyyymmdd'),'dd-mm-yyyy')

Please, please, please do not store DATEs and CHARACTER datatypes. This will only lead to issues that can be avoided when using the DATE datatype.

If you want to change the string 20170202 to another string and not actually a date (which would have no intrinsic formatted text representation), you could optionally use a regular expression to transform it, instead of converting to a date and back:
select regexp_replace('20170202 ', '^(\d{4})(\d{2})(\d{2}) +$', '\3-\2-\1')
from dual;
REGEXP_REPLACE(
---------------
02-02-2017
Or you could use substr instead of regexp_substr, which may perform better even if you have to call it three times; using a CTE just to avoid repeating the value:
with t(str) as (
select '20170202 ' from dual
)
select substr(str, 7, 2) ||'-'|| substr(str, 5, 2) ||'-'|| substr(str, 1, 4)
from t;
SUBSTR(STR
----------
02-02-2017
If you do convert to a date and back you would uncover any values which cannot be converted, as they will cause an exception to be thrown. That would imply you have bad data; which would have been avoided by using the right data type in the first place, of course. These will convert any old rubbish, with varying results depending on how far the strings stray from the pattern you expect - but including strings like '20170231' which represent an invalid date. And null value or strings of just spaces will be converted to odd things with the substr version, but you could filter those out.
You can see the kind of variation you would get with some sample data that doesn't match your expectations:
with t(str) as (
select '20170202 ' from dual
union all select '20170231 ' from dual
union all select '2017020c ' from dual
union all select '2017020 ' from dual
union all select '201702021 ' from dual
union all select ' ' from dual
union all select null from dual
)
select str,
regexp_replace(str, '^(\d{4})(\d{2})(\d{2}) +$', '\3-\2-\1') as reg,
substr(str, 7, 2) ||'-'|| substr(str, 5, 2) ||'-'|| substr(str, 1, 4) as sub
from t;
STR REG SUB
------------- ------------- -------------
20170202 02-02-2017 02-02-2017
20170231 31-02-2017 31-02-2017
2017020c 2017020c 0c-02-2017
2017020 2017020 0 -02-2017
201702021 201702021 02-02-2017
- -
--
With the anchors and whitespace expectation, the regular expression doesn't modify anything that doesn't consist entirely of 8 numeric characters. But it can still form invalid 'dates'.

Related

How substr works on dates

I am trying to understand a query in my application where it uses substr function.
I have gone through the documentation for substr, which looks simple and clear.
Now below is my query without using substr:
select last_day(to_date(to_char(add_months(TO_DATE('2004/10/25', 'yyyy/mm/dd'),1),'YYYY')||'0201','YYYYMMDD')) from dual;
This gives me result as 2/29/2004. The above query just returns last day of Feb in simple words.
Now I am using substr as below:
select substr(last_day(to_date(to_char(add_months(TO_DATE('2004/10/25', 'yyyy/mm/dd'),1),'YYYY')||'0201','YYYYMMDD')),5,1) from dual;
So here the start value is 5 & length is 1, so I am expecting output as 2 looking at 2/29/2004. but the actual output is E, I am not clear from where this E is coming as result.
You cannot use SUBSTR() on DATE values. SUBSTR() works only on strings!
When you run SUBSTR({DATE_VALUE}, ...) then Oracle actually does following:
SELECT
SUBSTR(
TO_CHAR(
{DATE_VALUE}, (SELECT VALUE FROM nls_session_parameters WHERE parameter = 'NLS_DATE_FORMAT')
), ...
)
FROM dual;
What is the purpose of this query? Do you like to find out whether input year is a leap-year?
Try this instead -
select substr(to_char(last_day(to_date(to_char(add_months(TO_DATE('2004/10/25', 'yyyy/mm/dd'),1),'YYYY')||'0201','YYYYMMDD')),'dd/mm/yyyy'),5,1)
from dual;

Cannot SUM(TO_NUMBER(varchar2 field)) :ORA 01722 [ORACLE]

I have myfield as varchar2 type and I try to sum this field by using sum(to_number(myfield)) but the result is ORA-01722 invalid number.
before this error occured I used SUM(TO_NUMBER(REGEXP_REPLACE(BIKOU,'[[:alpha:]]', ''))) and it works but last week I put some decimal value in myfield so this code not work anymore.
Here is my example of data in myfield
10,12,13.5,NULL
If you're getting that error from a string like 13.5 then your session's NLS_NUMERIC_CHARACTERS seems to be set to use a comma as the decimal separator:
alter session set nls_numeric_characters=',.';
with your_table (bikou) as (
select '10' from dual
union all select '12' from dual
union all select '13.5' from dual
union all select null from dual
)
select SUM(TO_NUMBER(REGEXP_REPLACE(BIKOU,'[[:alpha:]]', '')))
from your_table;
SQL Error: ORA-01722: invalid number
You can either explicitly set the session to use a period as the decimal separator, or provide a format mask that uses a period:
select SUM(TO_NUMBER(REGEXP_REPLACE(BIKOU,'[[:alpha:]]', ''), '99999999.99999'))
from your_table;
SUM(TO_NUMBER(REGEXP_REPLACE(BIKOU,'[[:
---------------------------------------
35,5
Or use the decimal separator marker in the model and override the session's NLS setting:
select SUM(TO_NUMBER(REGEXP_REPLACE(BIKOU,'[[:alpha:]]', ''),
'99999999D99999', 'nls_numeric_characters=''.,'''))
from your_table;
SUM(TO_NUMBER(REGEXP_REPLACE(BIKOU,'[[:
---------------------------------------
35,5
The mask obviously has to be suitable for all the values you expect back from your regex; what I've used may not be quite right for your data.
This kind of issue is why you should not store numbers or dates as strings. Use the correct data type for your columns.

Extract date from string oracle

I have a column in which a string starts with - 'Chicago, IL, April 20, 2015 — and so on text here'. I want to extract the Date part from this string in Oracle. Any ideas on how to do this. I was able to find something for mm/dd/yyyy like below, but not for long date format.
SELECT REGEXP_SUBSTR(' the meeting will be on 8/8/2008', '[0-9]{1,}/[0-9]{1,}/[0-9]{2,}') FROM dual
You could use:
SELECT TO_DATE(
REGEXP_SUBSTR(
'Chicago, IL, April 20, 2015 — and so on text here',
'(JANUARY|FEBRUARY|MARCH|APRIL|MAY|JUNE|JULY|AUGUST|SEPTEMBER|'
|| 'OCTOBER|NOVEMBER|DECEMBER)'
|| '[[:space:]]+([012]?[0-9]|3[01])'
|| '[[:punct:][:space:]]+\d{4}',
1,
1,
'i'
),
'MONTH DD YYYY'
)
FROM DUAL;
If you want to validate the dates as well (so you don't get an error for February 29, 2001) then you could use a user-defined function:
CREATE FUNCTION parse_Date(
in_string VARCHAR2,
in_format VARCHAR2 DEFAULT 'YYYY-MM-DD',
in_nls_params VARCHAR2 DEFAULT NULL
) RETURN DATE DETERMINISTIC
AS
BEGIN
RETURN TO_DATE( in_string, in_format, in_nls_params );
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END;
/
And replace the TO_DATE( ... ) function with PARSE_DATE( ... )
If your columns value is always start with 'Chicago, IL, April 20, 2015 — and so on text here' then you could simly use SUBSTR instead of REGEXP_SUBSTR
SELECT
SUBSTR(column_name
,INSTR(column_name, ',', 1, 2) + 1
,INSTR(column_name, '—') - INSTR(column_name, ',', 1, 2) - 1
)
FROM
dual;
If not then you could use REGEXP_SUBSTR as other answer mention, my original answer is wrong as #MTO comment
Well, you can take a direct approach and use a regular expression like in the example that you've found:
SELECT
REGEXP_SUBSTR('Chicago, IL, April 20, 2015 - etc etc', '(January|February|March|April|May|June|July|August|September|October|November|December) [0-9]{1,2}, [0-9]{4}')
FROM dual;
But this will only work properly if all the dates are in the exact same format. Full month name with first letter uppercased, space, day, comma, space, 4-digit year. If there can be more than one space or no space at all, use \s* instead of spaces in the regular expression. If the month name isn't necessarily initcap, use initcap() on source or case-insensitive flag for regexp_substr function.
Additionally, this will catch bogus dates that fit the format, like "April 99, 1234", you'll have to filter them later.

Date Format conversion inaccurate results in oracle

SELECT substr(partition_name, 8, 16)
FROM all_tab_partitions
WHERE TABLE_owner IN (
'DATAMARTCORE'
,'DWHCORE'
)
AND TO_CHAR(TO_DATE(substr(partition_name, 8, 16), 'yyyy/mm/dd'), 'yyyy/mm/dd') <= to_char(to_date('2015/05/31', 'yyyy/mm/dd'))
The following query results in error - literal does not match format string
Want all partitions that are less than may
Partition_name column is in string format
According to documentation substr has the following specification:
SUBSTR(string, position, substring_length)
Note: position is 1-based (but if you put 0 it will imply 1)
So a substring length of 16 won't fit into "yyyy/mm/dd" which may explain the error message.
Furthermore I can't see any point in comparing dates by converting to strings where comparing dates would be sufficient.
So I have updated your SQL as:
SELECT substr(partition_name, 8, 16)
FROM all_tab_partitions
WHERE TABLE_owner IN ( 'DATAMARTCORE' ,'DWHCORE')
AND TO_DATE(substr(partition_name, 8, 10), 'yyyy/mm/dd') <= to_date('2015/05/31', 'yyyy/mm/dd')

Oracle - how to create date from an already existing date?

Say I issue:
select date_field from table1;
date_field is like '25.11.2009'
I will try to change the positions of date fields with the month and vice versa. (of course for days > 12 some manipulations)
TO_DATE( MOD(SUBSTR(TO_CHAR(a.A_DATE, 'DD.MM.YYYY'), 4, 2), 12) || '.' ||
SUBSTR(TO_CHAR(a.A_DATE, 'DD.MM.YYYY'), 1, 2) ||
SUBSTR(TO_CHAR(a.A_DATE, 'DD.MM.YYYY'), 6, 4),
'DD.MM.YYYY')
THE THING IS THAT THE VALUE RETURNED FROM MOD() function is a number, i.e. for 01.07.2009 --> I get 1 for date, not '01' as expected. Later on I cannot get the date.
Is there a shortcut solution to my problem?
I suspect you need to seriously reconsider what you are trying to do.
I think what you started with is that you want to simply change the formatting of the date, e.g. change '25.11.2009' to '11.25.2009'.
If date_field is actually a DATE type, there is no inherent formatting stored in the field. It is a numeric value representing a specific date and time. It is formatted into text when you SELECT it in SQLPlus or some other tool, but that formatting is not stored in the table.
If you want to view the date in a particular format, you use the TO_CHAR function to force it. You can also set a default format model for a single session, a single client, or the whole database using NLS_DATE_FORMAT.
I used:
CASE MOD(SUBSTR(TO_CHAR(a.birthday, 'DD.MM.YYYY'), 1, 2), 12)
WHEN 1 THEN '01'
WHEN 2 THEN '02'
WHEN 3 THEN '03'
WHEN 4 THEN '04'
WHEN 5 THEN '05'
WHEN 6 THEN '06'
WHEN 7 THEN '07'
WHEN 8 THEN '08'
WHEN 9 THEN '09'
WHEN 10 THEN '10'
WHEN 11 THEN '11'
WHEN 12 THEN '12'
END
not very elegant but works :)
yli> "I am somehow anonymising the date, actually Hire Date of employees, to be used in a test environment."
So here was your actual requirement. If you want to change some dates, you don't need to use the date/string conversion functions (TO_CHAR/TO_DATE) at all. Oracle supports arithmetic operations on date values directly.
If you want to randomize your dates why not just use something like:
select date_field + dbms_random.value * 100 from table1;
Does this work?
TO_DATE(TO_CHAR(a.A_DATE, 'DD/MM/YYYY'), 'MM/DD/YYYY')
Have you tried TO_CHAR(<date>, '<format>')?

Resources