【问题标题】:Is there a way to make an Oracle Job disable itself?有没有办法让 Oracle 作业自行禁用?
【发布时间】:2015-01-07 04:16:33
【问题描述】:

我正在努力做到这一点:

declare
  Contador number;

begin
 ATUALIZAR_VAL_MAT_PENDENTES(Contador);

 if Contador = 0 then
  dbms_scheduler.disable('JOB_ATUALIZAR_VAL_MAT_PEND');
  end if;
end;

当计数器返回零时,它将禁用这个 JOB。但是,我得到:

“ORA-27478:o 作业“SPEDO.JOB_ATUALIZAR_VAL_MAT_PEND” está em execução”

最后一位表示“它正在执行”

所以,我认为这是因为作业正在运行并且它无法自行关闭。

我认为另一种方法可能是更改结束日期,但我似乎找不到执行此操作的语法。

有人可以帮忙吗?这可以实现吗?

【问题讨论】:

  • 您正在尝试解决的哪些业务问题会导致您想要一份工作来禁用自己?从技术上讲,我想你可以提交一个新的工作,一旦它完成就禁用现有的工作。但是我很难想象我想要这种行为的情况,而不是,比如说,工作失败并且没有被重新执行或创建一个只运行固定次数的工作或一个只运行的工作有工作要做的时候。
  • 我需要运行一个程序来检查用户是否已偿还债务以及是否仍在到期日内。当它过期并且没有支付时,我会重新计算所有的价值,直到没有旧价值的债务。这种情况每年只发生一次,所以,我不需要永远检查它。 @贾斯汀洞穴
  • 我不确定我是否理解。听起来您是在说您正在尝试禁用该作业,而不是为该作业定义正确的时间表。如果您希望流程在年初的某几天内每天检查某事,然后在今年余下的时间里什么都不做,请为此定义一个时间表。
  • 我怎么知道它应该在什么时候停止?想象一下,如果您需要将某项服务的价值从 100 美元更改为 101 美元。但是,有几个客户的账单到期日尚未到期,因此,客户仍然可以支付旧价格。此外,您无法控制账单到期前的天数,因为该信息属于另一个系统并由另一个系统生成。只有当没有更多的账单可以修改价格时,这项工作才应该停止。 @贾斯汀洞穴
  • 如果是这样的话,我会让这项工作每天运行并接受到今年年底它几乎没有什么可做的(因此到最后应该几乎不需要时间年)。如果某个客户的到期日期可能是 12 月 30 日,那么禁用该作业一天就没有意义了。

标签: oracle plsql dbms-scheduler


【解决方案1】:

感谢@Shankar 的帮助。这就是我设法完成我想做的事情的方式:

declare
  Contador number;

begin
 ATUALIZAR_VAL_MAT_PENDENTES(Contador);

 if Contador = 0 then
   dbms_scheduler.set_attribute('JOB_ATUALIZAR_VAL_MAT_PEND', 'end_date', systimestamp + 1);
  end if;
end;

我已经想到了这一点,但是当智能感知弹出说“值”参数是“布尔值”时,我什至没有尝试将日期传递给它。现在它工作正常,但我认为我必须补充一点:

如果您尝试将结束日期设置为提前一小时或几分钟,这将不起作用。您需要实际更改日期,否则它会给您 ORA-27483: "string.string" has an invalid END_DATE。

【讨论】:

  • 感谢您的提示。实际上,end_date 在未来领先一秒就足够了:dbms_scheduler.set_attribute(jobName, 'end_date', systimestamp+1/24/60/60);
【解决方案2】:

我猜你可以做两件事,

  1. 强制停止作业,然后禁用它。
declare
  Contador number;    
begin
 ATUALIZAR_VAL_MAT_PENDENTES(Contador);

 if Contador = 0 then
  DBMS_SCHEDULER.stop_JOB (job_name => 'JOB_ATUALIZAR_VAL_MAT_PEND',force=>true);
  dbms_scheduler.disable('JOB_ATUALIZAR_VAL_MAT_PEND');
  end if;
end;
  1. 检查作业是否完成,然后禁用。
SELECT status FROM USER_SCHEDULER_JOB_LOG
WHERE job_name = 'JOB_ATUALIZAR_VAL_MAT_PEND' and operation = 'RUN' ORDER BY log_date desc
offset 0 rows fetch next 1 row only; -- This will give you the latest run's status

将其存储到一个变量中(比如 status_),然后像下面这样检查,

declare
  Contador number;

begin
 ATUALIZAR_VAL_MAT_PENDENTES(Contador);

 if Contador = 0 and status_ ="Succeeded" then
  DBMS_SCHEDULER.stop_JOB (job_name => 'JOB_ATUALIZAR_VAL_MAT_PEND',force=>true);
  dbms_scheduler.disable('JOB_ATUALIZAR_VAL_MAT_PEND');
  end if;
end;

【讨论】:

  • 但是,我正在尝试在我试图禁用的工作中进行此操作。您不认为强制停止会使其忽略第二个命令吗?此外,“contador”变量已经定义了操作的成功。这意味着它没有其他要处理的东西,它应该停止运行@Shankar
  • 哦,抱歉,您的问题完全错过了这一点。一个作业可以禁用自身,如果 - 如果它有一个已经过去的 end_date 集 - 如果它指向一个已被删除的程序 - 如果它有 max_runs 或 max_failures 集并且已经达到
  • 我怎样才能即时设置 end_date?我的意思是,当“contador”为零时,我想将 end_date 更改为 sysdate+1。有没有办法做到这一点? @香卡
  • 你试过了吗,开始 dbms_scheduler.set_attribute (name => '你的工作名称', attribute => 'end_date', value => '01-mar-2015 07:00:00 am' );结尾; end_date 是一个时间戳字段,仅供参考...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-22
  • 2018-02-08
  • 2021-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多