在Oracle

时间:2018-10-22 11:26:44

标签: oracle plsql database-trigger

我试图声明一个变量,然后再次访问它以为特定ID更新同一张表。(将STATUS'E'更新为'R'

create or replace trigger resume_trgr
before update on temp_jobs

DECLARE
job_status varchar(2);

begin
  select STATUS into :job_status from temp_jobs where id=6120;
  if :job_status='E'
  then
    update temp_jobs set STATUS='R' where id=6120;
  end if;
end;
/

但是在执行上述代码时返回错误。错误代码如下:

已触发触发器resume_trgr

 Errors: check compiler log

 Error(5,27): PLS-00049: bad bind variable 'STATUS'

2 个答案:

答案 0 :(得分:1)

您遇到的错误是……很好,很奇怪。一些评论:

  • 您的代码中没有变量STATUS
  • 选择变量时,不需要冒号(即不是into :job_status而是into job_status)。
  • 您应该使用VARCHAR2数据类型,而不是VARCHAR
  • 这可能应该是行级触发器(因此您错过了FOR EACH ROW),并且在修复所有问题后,会遇到变异表错误
  • 您为什么要硬编码ID?真的只为那个ID做某事吗?

您可能会做的是:首先,测试用例:

SQL> create table temp_jobs
  2    (id number,
  3     status varchar2(10));

Table created.

SQL> insert into temp_jobs values (1, 'E');

1 row created.

SQL> insert into temp_jobs values (6120, 'E');

1 row created.

SQL> select * from temp_jobs;

        ID STATUS
---------- ----------
         1 E
      6120 E

触发:请注意您和我的代码之间的区别。

SQL> create or replace trigger resume_trgr
  2    before update on temp_jobs
  3    for each row
  4  DECLARE
  5    JOB_STATUS VARCHAR2(2);
  6  begin
  7    :new.status := case when :old.status = 'E' then 'R'
  8                        else :new.status
  9                   end;
 10  end;
 11  /

Trigger created.

测试:

SQL> update temp_jobs set status = 'Y' where id = 6120;

1 row updated.

SQL> select * from temp_jobs;

        ID STATUS
---------- ----------
         1 E
      6120 R

SQL> update temp_jobs set status = 'Y' where id = 6120;

1 row updated.

SQL> select * from temp_jobs;

        ID STATUS
---------- ----------
         1 E
      6120 Y

SQL>

答案 1 :(得分:1)

在一个问题中,您说错误涉及STATUS,但与您发布的代码不匹配。您应该遇到两个错误,涉及JOB_STATUS

那是因为它被定义为局部变量,并且您试图将其称为绑定变量。它不应该带有冒号前缀;这样可以编译:

create or replace trigger resume_trgr
before update on temp_jobs
declare
  job_status temp_jobs.status%type;
begin
  select STATUS into job_status from temp_jobs where id=6120;
  if job_status='E'
  then
    update temp_jobs set STATUS='R' where id=6120;
  end if;
end;
/

这样做,它会完全跳过变量:

create or replace trigger resume_trgr
before update on temp_jobs
begin
  update temp_jobs set STATUS='R' where id=6120 and status = 'E';
end;
/

在触发器内执行的操作是有用,有效还是明智的事情是另一回事。似乎是一个单独的更新,您应该在“真实”更新之前手动进行,可能要在一个过程中进行-如果您确实要始终更新该特定ID的行,而不管您在“真实”中实际进行的其他操作(触发)更新。

如果您真正想做的是确保即使调用者没有明确地将状态更改为R,那么您可能想要一个行级触发器来设置伪行值,而不是而不是具有硬编码ID的语句级触发器。