第一次尝试学习oracle触发器

时间:2012-12-13 21:25:00

标签: oracle triggers

我刚刚开始学习触发器,所以请耐心等待。如果插入的行的礼物与表格中已有的礼物相同,请打印一条消息,说明礼物已经从捐赠者那里赠送给接收者。

create or replace TRIGGER Same_Gift_Given
  BEFORE INSERT ON GIVING
  FOR EACH ROW
DECLARE
  giftgiven varchar(255);
BEGIN
  SELECT giftname INTO giftgiven from GIVING;
  IF :new.giftname = giftgiven then
    dbms_output.put_line(giftgiven || ' has already been gifted to ' || giving.receiver || ' by ' || giving.donor);
  end if;
END;

2 个答案:

答案 0 :(得分:4)

这是一个非常糟糕的作业问题。在真实系统中,你永远不会让我们触发这样的事情。它将打破大多数INSERT操作,如果有多个用户,它将失败。实际上,您将使用约束。实际上,如果由于某种原因你被迫用枪指使用触发器,你需要一系列三个触发器,一个包和一个集合才能正确地完成它。

教授可能正在寻找什么

但是,要强调的是,你永远不会考虑在真实系统中这样做

create or replace trigger same_gift_given
  before insert on giving
  for each row
declare
  l_existing_row giving%rowtype;
begin
  select *
    into l_existing_row
    from giving
   where giftname = :new.giftname
     and rownum = 1;

  dbms_output.put_line( :new.giftname || 
                           ' has already been gifted to ' ||
                           l_existing_row.receiver ||
                           ' from ' ||
                           l_existing_row.donor );
exception
  when no_data_found
  then
    null;
end;

这不会阻止您插入重复的行。如果您尝试在INSERT ... VALUES表上执行除giving之外的任何操作,它将引发变异触发错误。效率低下。它不处理多个会话。简而言之,它绝对是一个绝不应该在任何真实系统中使用的恶意代码。

你会在现实中做些什么

实际上,你会创建一个约束

ALTER TABLE giving
  ADD CONSTRAINT unique_gift UNIQUE( giftname );

这将在多用户环境中起作用。它不会抛出变异触发器异常。效率更高。它的代码要少得多。它实际上可以防止插入重复的行。

答案 1 :(得分:0)

让我们尝试一些不同的东西:

CREATE OR REPLACE TRIGGER GIVING_COMPOUND_INSERT
  FOR INSERT ON GIVING
  COMPOUND TRIGGER

  TYPE STRING_COL IS TABLE OF VARCHAR2(255) INDEX BY VARCHAR2(255);

  colGiftnames   STRING_COL;
  aGiftname      VARCHAR2(255);
  nCount         NUMBER;

  -- Note that the way the associative array is used here is a bit of a cheat.
  -- In the BEFORE EACH ROW block I'm putting the string of interest into the
  -- collection as both the value *and* the index.  Then, when iterating the
  -- collection only the index is used - the value is never retrieved (but
  -- since it's the same as the index, who cares?).  I do this because I'd
  -- rather not write code to call a constructor and maintain the collections
  -- size - so I just use an associative array and let Oracle do the work for
  -- me.

  BEFORE EACH ROW IS
  BEGIN
    colGiftnames(:NEW.GIFTNAME) := :NEW.GIFTNAME;
  END BEFORE EACH ROW;

  AFTER STATEMENT IS
  BEGIN
    aGiftname := colGiftnames.FIRST;
    WHILE aGiftname IS NOT NULL LOOP
      SELECT COUNT(*)
        INTO nCount
        FROM GIVING
        WHERE GIFTNAME = aGiftname;

      IF nCount > 1 THEN
        DBMS_OUTPUT.PUT_LINE('Found ' || nCount || ' instances of gift ''' ||
                             aGiftname || '''');
        RAISE_APPLICATION_ERROR(-20001, 'Found ' || nCount ||
                                        ' instances of gift ''' ||
                                        aGiftname || '''');
      END IF;

      aGiftname := colGiftnames.NEXT(aGiftname);
    END LOOP;
  END AFTER STATEMENT;
END GIVING_COMPOUND_INSERT;

同样,这是一种尝试保证唯一性的LOUSY方式。实际上,执行此操作的“正确方法”是使用约束(UNIQUE或PRIMARY KEY)。仅仅因为可以做某事并不意味着应该

分享并享受。