Oracle触发器不起作用

时间:2013-12-17 18:47:21

标签: sql oracle triggers identifier

我正在尝试对此代码进行排序,并且它会进行编译,但是当我通过删除记录进行测试时,如果给出: 标识符无效

错误可能在:旧部分,但我无法理解。

这是我的代码。

create or replace trigger t_OnDeleteCategory
create or replace trigger t_OnDeleteCategory
before delete on Categorie
for each row
declare
 v_textMail  varchar2(2000);
 v_emailAdres MailAbonnee.emailAdres%type;
 v_Voornaam MailAbonnee.voornaam%type;
 v_Achternaam MailAbonnee.Achternaam%type;
 c_cursor SYS_REFCURSOR;
 v_sql varchar2(2000);
 v_categorienaam categorie.naam%type;
begin
 v_categorienaam := :old.naam;
--1) mailbericht verzenden
v_sql := 'select voornaam, achternaam, emailAdres from MailAbonnee where id in (select mailAbonneeID from CategorieAbonnement where categorieNaam = v_categorienaam)';
open c_cursor for v_sql;
loop
    fetch c_cursor into v_Voornaam, v_Achternaam, v_emailAdres;
    exit when c_cursor%notfound;
    v_textMail := 'Beste ' || v_Voornaam || ' ' || v_Achternaam || ', uw abonnement is opgeheven voor Categorie '|| v_categorienaam || '.';
    sendMailAbonnee(v_textMail, v_emailadres);
end loop;
--2) verwijder alle abonnementen
delete from CategorieAbonnement where categorieNaam = v_categorienaam;
--3) pas alle nieuwsberichten aan
update Nieuwsbericht set categorieNaam = '' where categorieNaam = v_categorienaam;
 end; 

2 个答案:

答案 0 :(得分:2)

就像@JustinCave建议的那样,你的动态SQL有问题。 v_categorienaam是一个变量,但它在SQL的字符串中。删除动态SQL,您的问题就会消失。

此外,您可以使用游标for循环来简化代码,例如:

create or replace trigger t_OnDeleteCategory
before delete on Categorie
for each row
declare
  v_textMail  varchar2(2000);
begin
  --1) mailbericht verzenden
  for c in (
    select voornaam, achternaam, emailAdres
    from MailAbonnee
    where id in (
      select mailAbonneeID from CategorieAbonnement where categorieNaam = :old.naam
    )
  ) loop
    v_textMail := 'Beste ' || c.voornaam || ' ' || c.achternaam || ', uw abonnement is opgeheven voor Categorie '|| c.naam || '.';
    sendMailAbonnee(v_textMail, c.emailadres);
  end loop;
  --2) verwijder alle abonnementen
  delete from CategorieAbonnement where categorieNaam = :old.naam;
  --3) pas alle nieuwsberichten aan
  update Nieuwsbericht set categorieNaam = '' where categorieNaam = :old.naam;
end;

答案 1 :(得分:1)

在这一行:

v_sql := 'select voornaam, achternaam, emailAdres from MailAbonnee where id in (select mailAbonneeID from CategorieAbonnement where categorieNaam = v_categorienaam)';

....你指的是v_categorienaam,但是当执行动态SQL时,这不是范围内的变量。您应该使用绑定变量:

v_sql := 'select voornaam, achternaam, emailAdres from MailAbonnee where id in (select mailAbonneeID from CategorieAbonnement where categorieNaam = :v_categorienaam)';

然后

open c_cursor for v_sql using v_categorienaam;

但正如其他人已经指出的那样,似乎没有任何理由让它变得充满活力。你可以摆脱v_sql而只是做:

open c_cursor for
  select voornaam, achternaam, emailAdres
  from MailAbonnee
  where id in (
    select mailAbonneeID
    from CategorieAbonnement
    where categorieNaam = v_categorienaam;

哪种格式和读取更容易,并且可以在解析/编译时验证,而不是在运行时给您任何潜在的错误。科林的版本更简单;你没有从显式获取中获得任何东西。