Search code examples
sqloracle-database

Oracle: not a valid month


I have a table with the following fields:

Reports (table name) Rep_Date (date) Rep_Time (date)

The Rep_Time field has values like '01/01/1753 07:30:00' i.e. the time part is relevant. I have written the following query:

select Reports.pid, MaxDate from Reports
INNER JOIN (
    select pid, max(TO_DATE(TO_CHAR(REP_DATE, 'DD/MM/YYYY')
        || TO_CHAR(REP_TIME, 'HH24:MI:SS'), 'DD/MM/YYYY HH24:MI:SS')) As MaxDate
    from reports
    group by pid
) ReportMaxDate
on Reports.PID = ReportMaxDate.PID
AND To_Date(To_Char(MaxDate, 'DD/MM/YYYY')) = REP_DATE
WHERE REPORTS.PID=61

The derived table part of the query runs, but when I run the entire query I get an error: "not a valid month". Why is this?

In order to help debug this; if I run the following query:

select rep_date, rep_time from reports where pid=61 and rownum=1

I get:

Rep_Date = 01/04/2009
Rep_Time = 01/01/1753 13:00:00

UPDATE 15:58 I am now able to execute the following query:

select Reports.pid, MaxDate from Reports
INNER JOIN (
    select pid, max(TO_DATE(TO_CHAR(REP_DATE, 'DD/MM/YYYY')
        || TO_CHAR(REP_TIME, 'HH24:MI:SS'), 'DD/MM/YYYY HH24:MI:SS')) As MaxDate
    from reports group by pid
) ReportMaxDate
on Reports.PID = ReportMaxDate.PID
AND to_date(to_char(maxdate,'MM/DD/YYYY'),'MM/DD/YYYY') = REP_DATE
WHERE REPORTS.PID=61

However, I need to add one more statement to the WHERE clause comparing the time part of MaxDate to rep_time: to_date(to_char(maxdate,'MM/DD/YYYY'),'MM/DD/YYYY') = REP_DATE does not work.


Solution

  • 1.

    To_Date(To_Char(MaxDate, 'DD/MM/YYYY')) = REP_DATE
    

    is causing the issue. when you use to_date without the time format, oracle will use the current sessions NLS format to convert, which in your case might not be "DD/MM/YYYY". Check this...

    SQL> select sysdate from dual;
    
    SYSDATE
    ---------
    26-SEP-12
    
    Which means my session's setting is DD-Mon-YY
    
    SQL> select to_char(sysdate,'MM/DD/YYYY') from dual;
    
    TO_CHAR(SY
    ----------
    09/26/2012
    
    
    SQL> select to_date(to_char(sysdate,'MM/DD/YYYY')) from dual;
    select to_date(to_char(sysdate,'MM/DD/YYYY')) from dual
                   *
    ERROR at line 1:
    ORA-01843: not a valid month
    
    SQL> select to_date(to_char(sysdate,'MM/DD/YYYY'),'MM/DD/YYYY') from dual;
    
    TO_DATE(T
    ---------
    26-SEP-12
    

    2.

    More importantly, Why are you converting to char and then to date, instead of directly comparing

    MaxDate = REP_DATE
    

    If you want to ignore the time component in MaxDate before comparision, you should use..

    trunc(MaxDate ) = rep_date
    

    instead.

    ==Update : based on updated question.

    Rep_Date = 01/04/2009 Rep_Time = 01/01/1753 13:00:00
    

    I think the problem is more complex. if rep_time is intended to be only time, then you cannot store it in the database as a date. It would have to be a string or date to time interval or numerically as seconds (thanks to Alex, see this) . If possible, I would suggest using one column rep_date that has both the date and time and compare it to the max date column directly.

    If it is a running system and you have no control over repdate, you could try this.

    trunc(rep_date) = trunc(maxdate) and 
    to_char(rep_date,'HH24:MI:SS') = to_char(maxdate,'HH24:MI:SS')
    

    Either way, the time is being stored incorrectly (as you can tell from the year 1753) and there could be other issues going forward.