2016-11-04 79 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