2016-11-04 78 views
0

我对PL/SQL相对比较陌生,我试图创建一个触发器,它会在表检查UPDATE后提醒我。当更新我想GE的用户名(User表),得分(审查表),以及产品名称(产品表),并打印出来:PL/SQL触发器变量问题

这是我到目前为止有:

3表格:

Review: score, userid,pid, rid 
Users: userid,uname 
Product: pid,pname 

所以Review可以使用forigen键引用其他表格。

create or replace trigger userNameTrigger 


    after insert on review 
    for each row 

    declare 


    x varchar(256); 
    y varchar(256); 
    z varchar(256); 


    begin 


    select uname into x , pname into y , score into z 
from review r , product p , users u 
where r.pid = p.pid and r.userid = u.userid and r.rid =new.rid; 




    dbms_output.put_line('user: '|| X||'entered a new review for Product: '|| Y || 'with a review score of: '|| Z); 


    end; 

我遇到的问题是我似乎无法弄清楚如何将选定的字段存储到变量并正确输出。

DDL:

Create Table Review 
    (
     score varchar2(100) 
     , userid varchar2(100) 
     , pid  varchar2(100) 
     , rid  varchar2(100) 
    ); 

Create Table Users 
(
    userid varchar2(100) 
    , uname varchar2(100) 
); 

Create Table Product 
(
    pid  varchar2(100) 
    , pname varchar2(100) 
); 
+0

使用dbms_output意味着只有执行插入的用户才会看到该消息 - 然后仅当他们启用了输出时 - 这有点没有意义。它只对调试非常有用/安全。你也总是会得到一个或多个行,所以不知道查询的要点是什么;当你查询触发器所反对的表时,你可能会遇到一个变异表错误 - 尽管这看起来并不是必须的。 –

回答

2

我能看到的第一个问题是,当你引用new.rid时,你错过了一个冒号。第二个是你在同一个表的行级触发器内访问审查表,这会在某个时刻给你一个变异的表错误;但不需要像插入行中的所有数据都在new pseudorow中。

create or replace trigger userNameTrigger 
after insert on review 
for each row 
declare 
    l_uname users.uname%type; 
    l_pname product.pname%type; 
begin 
    select u.uname into l_uname 
    from users u 
    where u.userid = :new.userid; 

    select p.pname 
    into l_pname 
    from product 
    where p.pid = :new.pid; 

    dbms_output.put_line('user '|| l_uname 
    || ' entered a new review for product ' || l_pname 
    || ' with a review score of '|| :new.score); 
end; 

更大的问题是,唯一能看到消息的人是用户插入了两行,这似乎有点无意义;并且他们必须在他们的会话中启用输出才能看到它。

如果您正在尝试记录日志,以便其他人可以看到它,然后将其存储在表中或写入文件。尽管无论如何都可以查看评论表,但似乎有点多余。

将所有表列作为字符串也不好 - 不要将数字值(例如分数,可能是ID字段)或日期存储为字符串,请使用正确的数据类型。它会在以后为你节省很多痛苦。您似乎也没有任何参照完整性(主键/外键)约束 - 因此您可以查看不存在的产品,例如,这会导致触发器中发现无数据发现异常。

+0

谢谢你的回答和建议! – user2402107

0

附: Table REVIEW中没有RID,所以我只是假设它应该是PID。

create or replace trigger userNameTrigger 
after insert on review 
for each row 
declare 

    x varchar2(256); 
    y varchar2(256); 
    z varchar2(256); 

BEGIN 

    select uname 
      , pname 
      , score 
    INTO x 
      , y 
      , z 
    from review r 
     , product p 
     , users u 
    where r.pid = p.pid 
    and r.userid = u.userid 
    and r.PID = :new.pid; 
    dbms_output.put_line('user: '|| X ||'entered a new review for Product: '|| Y || 'with a review score of: '|| Z); 

end userNameTrigger;  

你刚刚在INTO语句中犯了一个错误,你可以将它们聚集到一个INTO中。

+0

第1行出现错误: ORA-01422:精确提取返回的请求数多于 – user2402107

+0

此外,还有一个RID我进行了更新 – user2402107

+0

问题是我找不出如何记录新用户何时更新Review Table – user2402107

0

使用触发器通知自己有关更改的行是没有意义的。如果你在表格中插入新的行,那么你有关于它们的所有信息。为什么不喜欢的东西以下的块,而不是一个触发器:

create table reviews as select 0 as rid, 0 as userid, 0 as score, 0 as pid from dual where 1=0; 
create table users as select 101 as userid, cast('nobody' as varchar2(100)) as uname from dual; 
create table products as select 1001 as pid, cast('prod 1001' as varchar2(100)) as pname from dual; 

<<my>>declare newreview reviews%rowtype; uname users.uname%type; pname products.pname%type; begin 
    insert into reviews values(1,101,10,1001) returning rid,userid,score,pid into newreview; 
    select uname, pname into my.uname, my.pname 
    from users u natural join products p 
    where u.userid = newreview.userid and p.pid = newreview.pid 
    ; 
    dbms_output.put_line('user: '||my.uname||' entered a new review for Product: '||my.pname||' with a review score of: '||newreview.score); 
end; 
/

输出:user: nobody entered a new review for Product: prod 1001 with a review score of: 10

为了告知你应该使用DBMS_ALERT事件(交易)或DBMS_PIPE(非交易)封装另一个会话。 dbms_alert的一个例子:

create or replace trigger new_review_trig after insert on reviews for each row 
begin 
    dbms_alert.signal('new_review_alert', 'signal on last rid='||:new.rid); 
end; 
/

在另一个会话(新窗口,工作表,sqlplus或其他)中运行以下块。它会被阻止,直到登记的信号到达:

<<observer>>declare message varchar2(400); status integer; uname users.uname%type; pname products.pname%type; score reviews.score%type; 
begin 
    dbms_alert.register('new_review_alert'); 
    dbms_alert.waitone('new_review_alert', observer.message, observer.status); 
    if status != 0 then raise_application_error(-20001, 'observer: wait on new_review_alert error'); end if; 
    select uname, pname, score into observer.uname, observer.pname, observer.score 
    from reviews join users using(userid) join products using (pid) 
    where rid = regexp_substr(observer.message, '\w+\s?rid=(\d+)', 1,1,null,1) 
    ; 
    dbms_output.put_line('observer: new_review_alert for user='||observer.uname||',product='||observer.pname||': score='||observer.score); 
end; 
/

现在,在您的会话:

insert into reviews values(2, 101,7,1001); 
commit; --no alerting before commit 

的另一个(观察员)会议将与输出完成:
observer: new_review_alert for user=nobody,product=prod 1001: score=7