Search code examples
oracle-databaseoracle10gjobsdate-arithmetic

oracle 10g submit job function error


I'm trying to schedule a job in oracle 10g but it says:

ORA-01846: not a valid day of the week.

Heres my code:

declare
    v_job_id1 number(19,0);
    v_job_id2 number(19,0);
begin
    dbms_job.submit(v_job_id1, 'CTX_DDL.OPTIMIZE_INDEX(''PSO_KEYWORD_SEARCH_IDX'', ''FULL'', 45);', NEXT_DAY(TRUNC(SYSDATE), 4) + 13/24, NEXT_DAY(TRUNC(SYSDATE), 4) + 13/24 + 7 );
     commit;
end;
/

But this work as intended:

select NEXT_DAY(TRUNC(SYSDATE - 1), 4) + 13/24 from dual;

ANy ideas?

Thank you!

Udo


Solution

  • I can't explain why it happens, but Oracle accepts invalid NEXT_DAY(...) call syntax in plain SQL.

    But not in PL/SQL code. Try this:

    declare 
      d date;
    begin
      d := NEXT_DAY(TRUNC(SYSDATE), 4) + 13/24 + 7;
    end;
    

    and you got perfect ORA-01846 error.

    Oracle suggests workaround with switching NLS_DATE_LANGUAGE session parameter before calling NEXT_DAY to 'AMERICAN' and return it back after calculation.

    Example:

    DECLARE
    FUNCTION get_next_day(dn IN VARCHAR2,ln IN VARCHAR2) RETURN DATE IS
    CURSOR cr1 IS
    SELECT value
      FROM nls_session_parameters
     WHERE parameter = 'NLS_DATE_LANGUAGE';
    CURSOR cr2(dn1 IN VARCHAR2) IS
    SELECT next_day(SYSDATE,UPPER(dn1))
      FROM dual;
    day DATE;
    old_date_lang varchar2(128);
    BEGIN
      OPEN cr1;
      FETCH cr1 INTO old_date_lang;
      CLOSE cr1;
      dbms_session.set_nls('NLS_DATE_LANGUAGE',ln);
      OPEN cr2(dn);
      FETCH cr2 INTO day;
      CLOSE cr2;
      dbms_session.set_nls('NLS_DATE_LANGUAGE', old_date_lang);
      RETURN (day);
    END;
    BEGIN
      dbms_output.put_line(TO_CHAR(get_next_day('MONDAY','AMERICAN'),'DAY dd/mm/yyyy'));
    END;
    

    From my point of view better to avoid using NLS-aware functions at all, but day-of-a-week NLS-depended by definition: at some countries week starts from Sunday, at other countries - from Monday ...

    You can try to use TRUNC() function with 'D' option to lower NLS effect:

    select 
      NEXT_DAY(TRUNC(SYSDATE), 4)          as D1, 
      NEXT_DAY(TRUNC(SYSDATE), 'THU')      as D2, 
      case     
        -- next Thursday on this week
        when (TRUNC(SYSDATE,'D') + 4) > trunc(sysdate) then (TRUNC(SYSDATE,'D') + 4)
        -- next Thursday on next week
        else (TRUNC(SYSDATE,'D') + 4) + 7 
      end                                  as D3
    from dual
    

    In your case this looks like that:

    dbms_job.submit(
      JOB       =>  v_job_id1, 
      WHAT      => 'CTX_DDL.OPTIMIZE_INDEX(''PSO_KEYWORD_SEARCH_IDX'', ''FULL'', 45);',
      NEXT_DATE => (
                     case     
                       -- next Thursday on this week
                       when (TRUNC(SYSDATE,'D') + 4) > trunc(sysdate) then (TRUNC(SYSDATE,'D') + 4)
                       -- next Thursday on next week
                       else (TRUNC(SYSDATE,'D') + 4) + 7 
                     end               
                   ), 
      INTERVAL  => '
          case     
            when (TRUNC(SYSDATE,''D'') + 4) > trunc(sysdate) then (TRUNC(SYSDATE,''D'') + 4)
            else (TRUNC(SYSDATE,''D'') + 4) + 7 
          end               
      '
    );
    

    Update:

    Perfect workaround is to get name of the day from current NLS settings and use as day name. Because Aug-12-2010 definitely Thursday you can use it as base date to get day-of-the-week name:

    select to_char(to_date('20100812','yyyymmdd'), 'DAY') from dual  
    

    Then add name to function call instead of 4 constant:

    dbms_job.submit(
      JOB       =>  v_job_id1, 
      WHAT      => 'CTX_DDL.OPTIMIZE_INDEX(''PSO_KEYWORD_SEARCH_IDX'', ''FULL'', 45);',
      NEXT_DATE => NEXT_DAY(TRUNC(SYSDATE), to_char(to_date('20100812','yyyymmdd'), 'DAY')) + 13/24, 
      INTERVAL  => 'NEXT_DAY(TRUNC(SYSDATE), to_char(to_date(''20100812'',''yyyymmdd''), ''DAY'')) + 13/24 + 7'
    );