Date Format conversion inaccurate results in oracle - 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')

Related

Convert String to Date field for SQL 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'.

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.

Converting a timestamp value to number

I've a timestamp value in the format 2005-01-31T00:00:00.000-05:00. I want covert it to a number in the format20050131, to equate it to a column which has the datatype of number.
I tried to do it by to_number(to_date(timestamp, 'yyyymmdd')). But it is resulting in error not a valid month.
Could you please help me in resolving it.
try using like below
to_number(to_char(timestamp, 'yyyymmdd'))
first you have to convert to char and then to number.
If your timestamp value is a VARCHAR2 value, maybe this will help:
WITH tstmp AS (
SELECT '2005-01-31T00:00:00.000-05:00' AS val FROM dual
)
SELECT TO_NUMBER(TO_CHAR(FROM_TZ(TO_TIMESTAMP(SUBSTR(val, 1, 23), 'YYYY-MM-DD"T"HH24:MI:SS.FF3'), SUBSTR(val, 24)) , 'YYYYMMDD')) AS newval
FROM tstmp;

String Manipulation in Oracle 11g

I am currently working on an exercise that will display a certain text, say TESTTEMP, from a series of characters stored in a column. Example of the string:
PROGRAMNAME|MAX2112ETI_L;PROGRAMREV|L;TESTOPTION|FR;TESTTEMP|25;STD IPH|528.63436123348
Now what I need is to extract the text past the string TESTTEMP| and before the ;. What I did is I extracted all the text past TESTTEMP| and just get the first two character. Unfortunately, this will not be possible since there are cases where in the TESTTEMP| has 3 characters. Is there a way for me to be able to do this? Below is what I have so far:
SELECT
SUBSTR(SUBSTR(value, INSTR(value, ';TESTTEMP|')+10), 1, 2) invalue
FROM
(
SELECT
'PROGRAMNAME|MAX2112ETI_L;PROGRAMREV|L;TESTOPTION|FR;TESTTEMP|25;STD IPH|528.63436123348' VALUE
FROM dual
)t;
Find the index of ; in the substring and use that as index instead of hard coding it to 2.
SELECT
SUBSTR(SUBSTR(value, INSTR(value, ';TESTTEMP|')+10), 1, INSTR(SUBSTR(value, INSTR(value, ';TESTTEMP|')+10), ';')-1) invalue
FROM
(
SELECT
'PROGRAMNAME|MAX2112ETI_L;PROGRAMREV|L;TESTOPTION|FR;TESTTEMP|25;STD IPH|528.63436123348' VALUE
FROM dual
)t;
If that look messy, you can even write it like this
SELECT
SUBSTR(VALUE, 1, INSTR(VALUE, ';') - 1) invalue
FROM
(
SELECT
SUBSTR(VALUE, INSTR(VALUE, ';TESTTEMP|') + 10)
VALUE
FROM (
SELECT
'PROGRAMNAME|MAX2112ETI_L;PROGRAMREV|L;TESTOPTION|FR;TESTTEMP|25;STD IPH|528.63436123348'
VALUE
FROM dual) t
)t;
Based on comments - if you want to know if the string was found or not, use this query. FOUND will be greater than 0 if the string is found.
SELECT
SUBSTR(VALUE, 1, INSTR(VALUE, ';')-1) invalue, FOUND
FROM
(
SELECT
SUBSTR(VALUE, INSTR(VALUE, SEARCHSTRING)+10) VALUE, INSTR(VALUE, SEARCHSTRING) FOUND
FROM (
SELECT
'PROGRAMNAME|MAX2112ETI_L;PROGRAMREV|L;TESTOPTION|FR;TESTTEMP|25;STD IPH|528.63436123348'
VALUE,
';TESTTEMP|' SEARCHSTRING
FROM dual) t
)t;

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