views:

81

answers:

3

hi all,

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

+2  A: 

Interval parameter must be a string with SQL expression, executed by Oracle when calculating date and time of next run.

Therefore expression must be quoted:

dbms_job.submit(
  JOB       =>  v_job_id1, 
  WHAT      => 'CTX_DDL.OPTIMIZE_INDEX(''PSO_KEYWORD_SEARCH_IDX'', ''FULL'', 45);',
  NEXT_DATE => NEXT_DAY(TRUNC(SYSDATE), 4) + 13/24, 
  INTERVAL  => 'NEXT_DAY(TRUNC(SYSDATE), 4) + 13/24 + 7'
);
ThinkJet
@ThinkJet: It keeps saying is not a valid day thou. Thank you anyway.
Udo Fholl
+1  A: 

I'm posting this as an answer instead of a comment to allow better code formatting. ThinkJet's comment about the interval parameter is a valid point, and I still think your problem is related to the '4' arg to NEXT_DAY - for example, this code works:

SQL> declare
  2      v_job_id1 number(19,0);
  3      v_job_id2 number(19,0);
  4  begin
  5      dbms_job.submit(v_job_id1,
  6        'begin null; end;',
  7        NEXT_DAY(TRUNC(SYSDATE), 'Thursday') + 13/24,
  8        'NEXT_DAY(TRUNC(SYSDATE), '||chr(39)||'Thursday'||chr(39)||') + 13/24 + 7' );
  9       commit;
 10  end;
 11  /

PL/SQL procedure successfully completed.
dpbradley
@dpbradley: Thanks but I need it to be nls independent.
Udo Fholl
+1  A: 

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'
);
ThinkJet
@ThinkJet: this would still be nls dependent. Isnt there a way to set a job to run every Thursday at a given time (ie. 1pm)? Thanks
Udo Fholl
@ThinkJet - I think the difference between issuing the call from SQL vs. PL/SQL is that with PL/SQL you're using the NLS parameters of the database instead of the client settings.
dpbradley
Answer updated. I hope that it is NLS-independent solution ...
ThinkJet
@dpbradley : Hmm ... `4` is name for Thursday in Spanish? ...
ThinkJet
@ThinkJet: very clever solution! Thank you.@dpbradley and ThinkJet: Thank you!
Udo Fholl
@dpbradley: 4 is not, but Jueves is. So if I type 4 it is Jueves and also Thursday, at least, as far I knew when I was working in that solution.
Udo Fholl
4 is number and not valid abbreviation for any day of the week. If you read official documantation ( http://download.oracle.com/docs/cd/B28359_01/olap.111/b28126/dml_functions_2037.htm ) there are no possibilities to substitute name of the day with number of the day ...
ThinkJet
Thank you, I just tried and it worked in SQL, so I supposed it to work with PLSQL aswell.
Udo Fholl