可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have following query (BOCRTNTIME - varchar e.g 2015-02-28 12:21:45, VIEW_BASE_MARIX_T - some view
):
select BOCRTNTIME from VIEW_BASE_MARIX_T where to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') between (to_date ('2016-01-01', 'YYYY-MM-DD')) and (to_date ('2016-02-01', 'YYYY-MM-DD'))
On executing I get error:
ORA-01839: "date not valid for month specified"
I thought that there are can be incorrect data in BOCRTNTIME
, so execute following query:
select distinct substr(BOCRTNTIME,1,8), substr(BOCRTNTIME,9,2) from VIEW_BASE_MARIX_T order by substr(BOCRTNTIME,9,2);
But everything looks fine: http://pastebin.com/fNjP4UAu. Also following query executes without any error:
select to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') from VIEW_BASE_MARIX_T;
I already tried add trunc()
to all to_date()
but no luck. Also I create pl/sql procedure that takes one by one item form VIEW_BASE_MARIX_T
and convert it to date - and everything works just fine. Any ideas why I get error on first query?
UPD: Query on table that used in view works fine, but in view - not
UPD2: We have few enviroments with same products, but get error only on one
UPD3: Issue was resolved by search non valid dates in table that used in view
回答1:
I think that what might be happening is that Oracle is pushing the predicate to the underlying tables of the view.
Have you tried to run the query
select to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') BOCRTNTIME from MY_TABLE
instead of querying the view?
you can also confirm this by using the NO_PUSH_PRED hint
select /*+ NO_PUSH_PRED(VIEW_BASE_MARIX_T) */ BOCRTNTIME from VIEW_BASE_MARIX_T where to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') between (to_date ('2016-01-01', 'YYYY-MM-DD')) and (to_date ('2016-02-01', 'YYYY-MM-DD'))
回答2:
A bit too long for a comment - create a simple function to test the dates:
CREATE FUNCTION is_Valid_Date( in_string VARCHAR2, in_format VARCHAR2 DEFAULT 'YYYY-MM-DD' ) RETURN NUMBER DETERMINISTIC AS dt DATE; BEGIN dt := TO_DATE( in_string, in_format ); RETURN 1; EXCEPTION WHEN OTHERS THEN RETURN 0; END; /
Then you can do:
SELECT BOCRTNTIME FROM VIEW_BASE_MARIX_T WHERE is_Valid_Date( substr(BOCRTNTIME,1,10) ) = 0;
You will possibly find that April, June, September or November have an entry for the 31st of that month or February has values greater than 28/29th (although I can't see anything like that in your pasted data).
Otherwise you could try using ANSI Date literals:
SELECT BOCRTNTIME FROM VIEW_BASE_MARIX_T WHERE to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') between DATE '2016-01-01' and DATE '2016-02-01';
or, even simpler, given the format of the input:
SELECT BOCRTNTIME FROM VIEW_BASE_MARIX_T WHERE substr(BOCRTNTIME,1,10) between '2016-01-01' and '2016-02-01';
回答3:
The error message says that you have an invalid day in your month. Check your data with this:
-- Check for months with 30 days select substr(BOCRTNTIME,9,2), substr(BOCRTNTIME,6,2) from VIEW_BASE_MARIX_T where to_number(substr(BOCRTNTIME,6,2)) in (4,6,9,11) and to_number(substr(BOCRTNTIME,9,2))>30; -- Check for february select substr(BOCRTNTIME,9,2), substr(BOCRTNTIME,6,2) from VIEW_BASE_MARIX_T where to_number(substr(BOCRTNTIME,6,2))=2 and to_number(substr(BOCRTNTIME,9,2))>28;
回答4:
It might be a long shot but between doesn't have parenthesis in it's syntax, have you tried removing them?
select BOCRTNTIME from VIEW_BASE_MARIX_T where to_date(substr(BOCRTNTIME,1,10),'YYYY-MM-DD') between to_date ('2016-01-01', 'YYYY-MM-DD') and to_date ('2016-02-01', 'YYYY-MM-DD')