2016-04-24 6 views
1

私は、指定された値が別のテーブルの外部キーに間違った名前であるテーブルの1つに挿入をキャッチするOracleトリガを作成しようとしています。だからトリガーは与えられた名前ではなく、その名前を正しい名前に変更する必要があります。Oracle PL/SQLのトリガ - 間違った名前の挿入をキャッチする

私のデータベーステーブルがそうのような設定です:

SIGHTINGS (NAME, PERSON, LOCATION, SIGHTED) 
FEATURES (LOCATION, CLASS, LATITUDE, LONGITUDE, MAP, ELEV) 
FLOWERS (GENUS, SPECIES, COMNAME) 

テーブルは以下の意味があります。

  • 目撃することはクラブのメンバーは、野生の花の1を観察するたびに記述する情報を提供します表FLOWERSに記載されている。 NAMEは観察された花の名前を示し、PERSONは誰が花を見たかを示し、LOCATIONは花が見られた近くの地形の名前を示し、SIGHTEDは花が見られた日を示します。
  • FLOWERSには、クラブのメンバーが見つけようとしているすべての花が掲載されています。私はへの挿入をキャッチトリガーを設定しようとしています

(SIGHTING.NAMEがFLOWER.COMNAMEへの外部キーである)属および種は花のための科学的な名前を付け、そしてCOMNAMEは非科学的な名前を与えますSIGHTINGSテーブル。ユーザーが誤って共通名の代わりに花の科学的名称を挿入したとき。例えば、彼らが使用する可能性があります:

INSERT INTO SIGHTINGS VALUES 
    ('Chaenactis douglasii', 'Person A', 'Shirley Peak', TO_DATE('18-Aug-06', 'DD-MON-YY')); 

の代わりに:

INSERT INTO SIGHTINGS VALUES 
    ('Douglas dustymaiden', 'Person A', 'Shirley Peak', TO_DATE('18-Aug-06', 'DD-MON-YY')); 

を私はトリガがこの問題をキャッチし、画面に警告メッセージを出力して、データベースに共通の名前を挿入したいです、むしろラテン語の名前。

私のコードはそうのようになります。

CREATE OR REPLACE TRIGGER Used_Latin_Name 
BEFORE INSERT ON SIGHTINGS 
FOR EACH ROW 
WHEN (NEW.NAME IS NOT NULL) 
DECLARE 
    -- local variables 
    inserted_name VARCHAR2(30); 
    comm_name  VARCHAR2(30); 
    Invalid_name  EXCEPTION; 
    Valid_name  EXCEPTION; 
    -- local cursor 
    CURSOR c (name_in VARCHAR2) IS 
     SELECT COMNAME 
     FROM FLOWERS 
     WHERE COMNAME = name_in; 

BEGIN 
    -- open cursor and fetch a match 
    OPEN c(:NEW.NAME); 
    FETCH c INTO inserted_name; 
    CLOSE c; 

    -- Raise an exception when foreign key is invalid 
    IF inserted_name IS NULL THEN 
     RAISE Invalid_name; 
    ELSE 
     RAISE Valid_name; 
    END IF; 
EXCEPTION 
    WHEN Invalid_name THEN 
     CREATE INDEX genusindex on FLOWERS(GENUS) 
      indextype is ctxsys.ctxrule; 
     SELECT COMNAME FROM FLOWERS 
     INTO comm_name 
     WHERE matches(GENUS, :NEW.NAME) > 0; 
     DROP INDEX genusindex; 
     DBMS_OUTPUT.PUT_LINE ('Warning: Your insert into the SIGHTINGS table seemed to use the Latin name "' || :NEW.NAME || '" for the flower "' || comm_name '". I used the common name instead.'); 
    WHEN Valid_name 
     NULL; 
END; 
/

私はエラーを取得するかのよりも、この他を行うための別の方法がある場合は、私は、インデックスを作成していたインデックスを作成することはできませんので、私は思っていたこと私がそれをやっているやり方、あるいはどこか別の場所にインデックスを挿入しようとしている場合です。私はこれを助けるためにあらゆる場所で検索し、それを理解する運がなかった。

+0

あなたの質問には、実際に使用しているデータベースにのみタグを付けてください。 –

+3

最初に、トリガーにインデックスを作成することはできません。第二に、あなたはしたくないでしょう。索引、特にOracle Text索引を作成するのは遅い操作です。索引を作成してすぐに削除するのは意味がありません。第3に、Oracle Textの索引が必要ですか。標準索引を使用するだけでなく、まったく同じようなチェックを行うよりも、参照を実行する必要がありますか。第四に、あなたが実際に外部キーの制約を持っていると、トリガが鳴る前に違反する可能性があります。第5に、これはおそらくトリガーで実行する必要があるものではなく、アプリに属しています。 –

+0

あなたの解決策にはより多くの問題があります。もし '' COMMENT FROM FLOWERS''がcomm_nameに一致する場合は(GENUS、:NEW。NAME)> 0; 'が複数の行を返した場合、エラーが発生します。もう一つの問題は、 'DBMS_OUTPUT'は通常、ユーザにメッセージを出力するのではなく、デバッグに使用されます。プロダクション・コードでそれを使用すると、遅かれ早かれ、 'ORA-20000 DBMSバッファーのオーバーフロー 'が発生します。 – krokodilko

答えて

0

UPDATE

私は私がしようとしていたし、コードはとてもどのように見えるかの解決策を考え出した:

CREATE OR REPLACE TRIGGER Used_Latin_Name 
BEFORE INSERT ON SIGHTINGS 
FOR EACH ROW 
WHEN (NEW.NAME IS NOT NULL) 
DECLARE 
    -- local variables 
    inserted_name VARCHAR2(30); 
    comm_name  VARCHAR2(30); 
    Invalid_name EXCEPTION; 
    Valid_name  EXCEPTION; 
    -- local cursor 
    CURSOR c (name_in VARCHAR2) IS 
     SELECT COMNAME 
     FROM FLOWERS 
     WHERE COMNAME = name_in; 
BEGIN 
    -- open cursor and fetch a match 
    OPEN c(:NEW.NAME); 
    FETCH c INTO inserted_name; 
    CLOSE c; 


    -- Raise an exception when foreign key is invalid 
    IF inserted_name IS NULL THEN 
     RAISE Invalid_name; 
    ELSE 
     RAISE Valid_name; 
    END IF; 
EXCEPTION 
    WHEN Invalid_name THEN 
     SELECT COMNAME 
     INTO comm_name 
     FROM FLOWERS 
     WHERE GENUS = SUBSTR (:NEW.NAME, 1, INSTR(:NEW.NAME, ' ') - 1); 
     DBMS_OUTPUT.PUT_LINE ('Warning: Your insert into the SIGHTINGS table  seemed to use the Latin name ''' || :NEW.NAME || ''' for the flower ''' || comm_name || '''. I used the common name instead.'); 
     :NEW.NAME := comm_name; 
    WHEN Valid_name THEN 
     NULL; 
END; 
/

私は最初のホワイトスペースを検出するために、SUBSTRやINSTRを使用し、そのサブストリングが形成された正しいエントリーを見つけます。

関連する問題