1

我正在尝试在 oracle 10g 中安排工作,但它说:

ORA-01846: 一周中的某一天无效。

这是我的代码:

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;
/

但这项工作按预期工作:

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

有任何想法吗?

谢谢!

你做

4

4 回答 4

2

间隔参数必须是一个带有 SQL 表达式的字符串,由 Oracle 在计算下次运行的日期和时间时执行。

因此必须引用表达式:

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'
);
于 2010-08-12T12:11:48.427 回答
1

我将其发布为答案而不是评论,以允许更好的代码格式。ThinkJet 关于间隔参数的评论是一个有效的观点,我仍然认为您的问题与 NEXT_DAY 的 '4' 参数有关 - 例如,此代码有效:

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.
于 2010-08-12T13:23:49.043 回答
1

我无法解释为什么会发生这种情况,但 Oracle 接受NEXT_DAY(...)纯 SQL 中的无效调用语法。

但不是在 PL/SQL 代码中。试试这个:

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

你得到了完美的 ORA-01846 错误。

Oracle 建议在将 NEXT_DAY 调用为“AMERICAN”之前切换 NLS_DATE_LANGUAGE 会话参数并在计算后将其返回。

例子:

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;

从我的角度来看,最好完全避免使用 NLS 感知功能,但根据定义,一周中的一天 NLS 取决于:在某些国家/地区,一周从星期日开始,在其他国家/地区 - 从星期一开始......

您可以尝试使用TRUNC()带有 'D' 选项的函数来降低 NLS 效果:

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

在您的情况下,这看起来像这样:

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               
  '
);

更新:

完美的解决方法是从当前 NLS 设置中获取日期名称并用作日期名称。因为 2010 年 8 月 12 日绝对是星期四,所以您可以使用它作为基准日期来获取星期几的名称:

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

然后将名称添加到函数调用而不是4常量:

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'
);
于 2010-08-12T13:35:05.293 回答
1

确保您使用的是根据区域设置的日期。例如:-“星期日”这一天应该用德语写成“Sonntag”。我遇到过类似的问题..:p

于 2011-12-12T11:07:26.537 回答