【问题标题】:How to add triggers to find average,sum and number of rating for each movie in movie database如何添加触发器以查找电影数据库中每部电影的评分平均值、总和和数量
【发布时间】:2020-03-24 06:34:09
【问题描述】:

我必须添加电影的平均评分和总评分!以下是我的桌子和跳跳虎!请改进此代码!

create table fanrating
  (
   mov_id number(10),
   rate_avg number(1,1),
   rate_sum number,
   rate_count number
   );    
create table rating 
   ( 
    mov_id number(10) references movie(mov_id),
    userid varchar(20),
    rev_star number,
    primary key(mov_id,rev_star)
    );

delimiter $$
create or replace trigger bi_rating_trg
  before insert on fanrating
  for each row
begin
  set rate_sum = 0;
  set rate_count = 0;
  set rate_avg = null;
end;
$$
create or replace trigger ai_rating_trg
  after insert on rating
  for each row
begin
  update fanrating
     set rate_sum   = rate_sum + new.rev_star,
         rate_count = rate_count + 1,
         rate_avg   = rate_sum / rate_count
   where mov_id = new.mov_id;
end;
$$ delimiter;  

在触发器中的所有 3 个 set 命令中都显示错误,并且错误称为遇到符号 $$,我使用的是 Oracle SQL Delevepor!

【问题讨论】:

    标签: oracle plsql oracle11g triggers


    【解决方案1】:

    一些反对意见:

    • 您不需要第一个(插入前)触发器
    • newold 值前面应该有冒号,即 :new:old
    • PL/SQL 中没有set 命令(至少,我对此一无所知)。如果你想设置一个变量到某个值,你可以使用my_variable := :new.rate_star;
    • 我没用过delimiter;不知道你打算用它做什么。标准分隔符是分号和斜线,我建议你使用它们

    这就是我会如何做你想做的事。

    表格优先:

    SQL> create table fanrating
      2    (mov_id     number(10),
      3     rate_avg   number,
      4     rate_sum   number,
      5     rate_count number
      6    );
    
    Table created.
    
    SQL> create table rating
      2     (mov_id    number(10),
      3      userid    varchar(20),
      4      rev_star  number,
      5      primary key(mov_id,rev_star)
      6     );
    
    Table created.
    

    触发器使用merge 命令,它也被称为“upsert”,因为它使用update(如果有匹配,我会这样做)或insert(如果没有匹配):

    SQL> create or replace trigger ai_rating_trg
      2    after insert on rating
      3    for each row
      4  begin
      5    merge into fanrating f
      6      using (select :new.rev_star rev_star,
      7                    :new.mov_id   mov_id
      8             from dual
      9            ) x
     10      on (f.mov_id = x.mov_id)
     11    when matched then update set
     12      f.rate_sum = f.rate_sum + :new.rev_star,
     13      f.rate_count = f.rate_count + 1,
     14      f.rate_avg = round((f.rate_sum + :new.rev_star) /
     15                         (f.rate_count + 1), 2)
     16    when not matched then insert values
     17      (:new.mov_id, :new.rev_star, :new.rev_star, 1);
     18  end;
     19  /
    
    Trigger created.
    

    测试:

    SQL> insert into rating (mov_id, userid, rev_star) values (1, 'Little', 3);
    
    1 row created.
    
    SQL> select * From fanrating;
    
        MOV_ID   RATE_AVG   RATE_SUM RATE_COUNT
    ---------- ---------- ---------- ----------
             1          3          3          1
    
    SQL> insert into rating (mov_id, userid, rev_star) values (1, 'Foot', 1);
    
    1 row created.
    
    SQL> select * From fanrating;
    
        MOV_ID   RATE_AVG   RATE_SUM RATE_COUNT
    ---------- ---------- ---------- ----------
             1          2          4          2
    
    SQL> insert into rating (mov_id, userid, rev_star) values (1, 'Scott', 4);
    
    1 row created.
    
    SQL> select * From fanrating;
    
        MOV_ID   RATE_AVG   RATE_SUM RATE_COUNT
    ---------- ---------- ---------- ----------
             1       2,67          8          3
    
    SQL> insert into rating (mov_id, userid, rev_star) values (2, 'Foot', 5);
    
    1 row created.
    
    SQL> select * From fanrating;
    
        MOV_ID   RATE_AVG   RATE_SUM RATE_COUNT
    ---------- ---------- ---------- ----------
             1       2,67          8          3
             2          5          5          1
    
    SQL>
    

    [编辑:过程 + 触发器]

    如果它必须是一个过程,那么 - 正如我所评论的 - 将 MERGE 移入其中,使用您插入的值作为参数。方法如下:

    程序:

    SQL> create or replace procedure p_mrg
      2    (par_mov_id   in number,
      3     par_userid   in varchar2,
      4     par_rev_star in number
      5    )
      6  as
      7  begin
      8    merge into fanrating f
      9      using (select par_rev_star rev_star,
     10                    par_mov_id   mov_id
     11             from dual
     12            ) x
     13      on (f.mov_id = x.mov_id)
     14    when matched then update set
     15      f.rate_sum = f.rate_sum + par_rev_star,
     16      f.rate_count = f.rate_count + 1,
     17      f.rate_avg = round((f.rate_sum + par_rev_star) /
     18                         (f.rate_count + 1), 2)
     19    when not matched then insert values
     20      (par_mov_id, par_rev_star, par_rev_star, 1);
     21  end;
     22  /
    
    Procedure created.
    

    Trigger 现在调用过程(而不是运行MERGE 本身):

    SQL> create or replace trigger ai_rating_trg
      2    after insert on rating
      3    for each row
      4  begin
      5    p_mrg (:new.mov_id, :new.userid, :new.rev_star);
      6  end;
      7  /
    
    Trigger created.
    

    附加测试:

    SQL> insert into rating (mov_id, userid, rev_star) values (2, 'Mike', 2);
    
    1 row created.
    
    SQL> select * from fanrating;
    
        MOV_ID   RATE_AVG   RATE_SUM RATE_COUNT
    ---------- ---------- ---------- ----------
             1       2,67          8          3
             2        3,5          7          2
    
    SQL> 
    

    【讨论】:

    • 谢谢!我可以使用存储过程和触发器来执行相同的任务吗?求平均、总和、计数率的存储过程!!
    • 不客气。存储过程?我想 INSERT 和 MERGE 将是其中的一部分,而 MOV_ID、USERID 和 REV_STAR 将是过程的参数。
    • 存储过程和触发器做同样的任务!求平均、总和、计数率的存储过程!!你能帮我使用存储过程吗,因为我必须在我的 dbms 迷你项目中包含一个触发器和一个过程!
    • 我通过添加过程 + 触发器选项来编辑我的答案。请看一下。
    • “一些错误”很难调试,您必须提供更多信息。此外,它在我的示例中有效,所以......你做了你不应该做的事情。啊哈,那个错误。您是否将表 FANRATING 的 RATE_AVG 数据类型修改为 NUMBER(和我一样)?
    【解决方案2】:

    fanrating表不需要创建这样的触发器,但需要在创建过程中定义默认值如:

    create table fanrating
      (
       mov_id     number(10),
       rate_avg   number(1,1),
       rate_sum   number default 0,
       rate_count number default 0
       );
    

    并为rating 表创建insert or update 触发器:

    create or replace trigger ai_rating_trg 
    after insert or update on rating
      for each row
    begin 
    update fanrating 
       set rate_sum = nvl(rate_sum,0) + nvl(:new.rev_star,0),
           rate_count = nvl(rate_count,0) + 1,
           rate_avg = nvl(rate_sum,0) / nvl(rate_count,1)
     where mov_id = :new.mov_id;
    end;
    /
    

    其中nvl(..,0) 用于将null 值转换为zero

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-27
      • 2019-04-19
      • 2016-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多