1

BEFORE INSERT TRIGGER は、次のことを行う必要があります。

  • 年齢差が 10 歳を超える 2 人の患者を同じ部屋に割り当てることを禁止します。
  • さらに、トリガーは、許容年齢 (10 歳以下) の 2 人の患者が同じベッドに割り当てられることも禁止する必要があります。

つまり、次のことを意味します。

  • 新しい患者が、すでに入院しているどの患者よりも約 10 歳大きい場合、同じ部屋にいることはできません。
  • 新しい患者が、すでに入院している患者から 10 年未満の場合、同じ部屋にいることはできますが、同じベッドにいることはできません。

患者テーブルの構造:

   PAT_ID         CHAR
   PAT_NAME       CHAR
   PAT_GENDER     CHAR
   PAT_AGE        NUMBER
   PAT_ADMIT_D    CHAR
   PAT_WING       CHAR
   PAT_ROOM#      NUMBER
   PAT_BED        CHAR

これまでのところ、私のコードは次のとおりです。

   CREATE OR REPLACE TRIGGER assignmentcheck 
   before insert on patient
   for each row

   declare
        cursor p1_cursor is
             select pat_age, pat_room#, pat_bed from patient;

   agediff number;
   begin

        for p1_pat in p1_cursor loop
        agediff :=  p1_pat.pat_age - :new.pat_age;
        if (agediff >10) then
             if (:new.pat_room# = p1_pat.pat_room#) then
             raise_application_error(-20001, 'Age difference greater than 10     cannot be in the same room');
        end if;
        else if (:new.pat_room# = p1_pat.pat_room#) and (:new.pat_bed =  p1_pat.pat_bed) then
        raise_application_error(-20002, 'Age difference less than 10 cannot be on the same bed');
        end if;
        end if;
  end loop;

 end;
 /

いくつかのテストSQL:

 insert into patient values ('AZ24523', 'Zhou, Alicia', 'F', 24, '14-APR-2015', 'A', 20, 'B');
 insert into patient values ('JA33234', 'Abbott, John', 'M', 50, '14-APR-2015', 'A', 16, 'B');
 insert into patient values ('AN32676', 'Newman, Andrew', 'M', 10, '14-APR-2015', 'A', 16, 'B');
 insert into patient values ('ZZ24523', 'Zhang, Zhaoping', 'F', 38, '14-APR-2015', 'A', 16, 'A');

トリガーは、新しい行をテーブルに既に存在する行と比較することを想定しています。しかし、これまでのところ、私のトリガーは新しい行のみを比較しており、既にテーブルにある行とは比較していません。

期待どおりに動作させるにはどうすればよいですか?私はどこでも検索してきましたが、テーブル/データベース全体と比較する方法が見つかりません。

どうもありがとうございました。

4

2 に答える 2

0

良いニュース:トリガーが機能します (完全ではありませんが、ほとんど)。

どういう意味かわかりませんが、これまでのところ、私のトリガーは新しい行のみを比較しており、既にテーブルにある行とは比較していません。 トリガーは明らかに、テーブル内の既存の行をチェックします。正常に動作します。もちろん、テーブルを作成し、競合する行を挿入し、次にトリガーを作成すると、以前の挿入は修正されません。別の方法で削除または更新する必要があります。

悪いニュース:ここのように 1 回の選択で複数の行を挿入しようとすると、トリガーが機能しません。エラーが発生しますSQL Error: ORA-04091: table CHRIS.PATIENT is mutating, trigger/function may not see it

insert into patient  
  select 'AZ24523', 'Zhou',   'F', 24, '2015-04-14', 'A', 20, 'B' from dual union all
  select 'JA33234', 'Abbott', 'M', 50, '2015-04-14', 'A', 16, 'B' from dual union all
  select 'AN32676', 'Newman', 'M', 10, '2015-04-14', 'A', 16, 'B' from dual union all
  select 'ZZ24523', 'Zhang',  'F', 38, '2015-04-14', 'A', 16, 'A' from dual;

この状況で何ができるでしょうか?Oracle 11g では、コードを複合トリガーに変更できます。

create or replace trigger assignmentcheck 
for insert on patient compound trigger

  type patients_t is table of patient%rowtype;
  v_patients patients_t := patients_t();
  v_patient patient%rowtype;

before statement is begin
  select * bulk collect into v_patients from patient; 
end before statement;

before each row is begin
  v_patients.extend;
  v_patients(v_patients.last).pat_id := :new.pat_id;
  v_patients(v_patients.last).pat_age := :new.pat_age;
  v_patients(v_patients.last).pat_room# := :new.pat_room#;
  v_patients(v_patients.last).pat_bed := :new.pat_bed;
end before each row;

after each row is begin
  for i in 1..v_patients.count() loop
    v_patient := v_patients(i);
    if v_patient.pat_id<>:new.pat_id then 
      if v_patient.pat_room# = :new.pat_room# then 
        if abs(v_patient.pat_age-:new.pat_age) > 10 then 
          raise_application_error(-20001, 'Age difference to big');
        elsif v_patient.pat_bed = :new.pat_bed then
          raise_application_error(-20002, 'Bed already taken');
        end if;
      end if;
    end if;
  end loop;
end after each row;

end assignmentcheck;

以前の Oracle バージョンでは、この記事で説明されている解決策の 1 つを使用できます: Mutating Table Exceptions

于 2015-05-03T23:47:19.530 に答える