2016-12-10 5 views
-1

Oracle PL SQLでIf_Exists()スタイルの文を使用するソリューションを探しています。私はメンバーがgunsOwnedテーブルに所有されている新しい銃を入力しようとすると、特定のairsoft銃がgunsテーブルに存在するかどうかを確認するトリガーを作成しようとしています。銃が銃テーブルに存在しない場合は、銃がgunsOwnedテーブルに入力される前にテーブルに入力する必要があります。また、gunsOwnedのMakeとModelがMakeとModelの外部キーであるため参照整合性に違反しますGunsテーブルに表示されます。しかし、私はトリガーがコンパイルエラーで作成され続けると、私のすべての属性名が正しいので、なぜselect case文が機能していないのかわかりません。コードは次のとおりです。OracleでNOT EXISTSを使用するSELECT CASE

CREATE TRIGGER updateGuns 
BEFORE INSERT ON GunsOwned 
FOR EACH ROW 
DECLARE 
    MemberAddingGun NUMBER; 
    NewMake VARCHAR2(30); 
    NewModel VARCHAR2(30); 
BEGIN 
    MemberAddingGun := :NEW.OwnerID; 
    NewMake := :NEW.MakeOwned; 
    NewModel := :NEW.ModelOwned; 
    SELECT CASE gunExists 
    WHEN NOT EXISTS(SELECT Make, Model FROM Guns WHERE Make=NewMake AND Model=NewModel) 
    THEN 
    INSERT INTO Guns VALUES(NewMake, NewModel); 
    END 
    UPDATE Member 
    SET NumOfGuns = NumOfGuns+1 
    WHERE MemberID = MemberAddingGun; 
END updateGuns; 
. 
RUN; 

助けてもらえますか?

ありがとうございます!

答えて

0

使用簡単なINSERT ... SELECT ... WHEREの代わりに、CASEまたはIF文:

INSERT INTO Guns(colname1, colname2) 
SELECT NewMake, NewModel FROM dual 
WHERE NOT EXISTS(
    SELECT null FROM Guns WHERE Make=NewMake AND Model=NewModel 
); 

ところで - いつも、失敗したレコードのない、存在をチェックマルチユーザー環境にコミットわけではないので、レコードSQLでは表示されず、Gunsテーブルに重複したレコードが表示されます。
このような場合、何らかの同期が必要です。

0

だけで適切なフラグを設定した後IFを使用します。

DECLARE 
    v_flag number; 
BEGIN  
    SELECT (CASE WHEN EXISTS (SELECT 1 
          FROM Guns 
          WHERE Make = :New.MakeOwned AND Model = :New.Model AND rownum = 1; 
          ) 
       THEN 1 ELSE 0 
      END) 
    INTO v_flag 
    FROM DUAL; 

    IF v_flag = 0 
    THEN 
     INSERT INTO Guns(Make, Model) VALUES (:New.Make, :New.Model); 
    END IF; 

    UPDATE Member 
     SET NumOfGuns = NumOfGuns + 1 
     WHERE MemberID = :New.OwnerId; 
END; -- updateGuns 

私はローカル変数に:NEW内のフィールドをコピーするには何の利点を見ません。実際には、読者は値が:NEWレコードの値と異なるかどうかをチェックする必要があるため、コードを少し難しくしています。

しかし、代わりにGuns(Make, Model)にユニークなインデックスを設定し、挿入を試み、例外を使用してエラーを無視するだけです。

+0

これは、コンパイルエラーで作成されたトリガの警告を返しています。 Guns(Make、Model)属性が主キーを複合キーとして構成するのを参照してください。基本的には一意の言語インデックスです。 –

+0

@AndrewY。 。 。 'END IF'はコンパイルエラーを修正するかもしれません。 –

+0

コンパイルエラーがまだ分かりません。 v_flagが0でなければならないことがあります。存在しない場合はnullではありませんか? –

0

いくつかのオプションがあります。まず、あなたは、MERGE文を使用してこれを扱うことができます。

CREATE TRIGGER updateGuns 
    BEFORE INSERT ON GunsOwned 
    FOR EACH ROW 
BEGIN 
    MERGE INTO GUNS 
    USING (SELECT MAKE, MODEL FROM GUNS) g 
     ON (g.MAKE = :NEW.MAKEOWNED AND g.MODEL = :NEW.MODELOWNED) 
    WHEN NOT MATCHED THEN 
    INSERT (MAKE, MODEL) 
     VALUES (:NEW.MAKEOWNED, :NEW.MODELOWNED); 

UPDATE Member 
    SET NumOfGuns = NumOfGuns+1 
    WHERE MemberID = :NEW.OWNERID; 
END UPDATEGUNS; 

この場合、MERGEは、指定された製造元とモデルがすでにテーブルに存在しない場合にのみGUNSに新しい行を追加し、条件付きのINSERTとして働き。

また、MAKEとMODELが主キーまたはGUNSの一意のキーであると仮定すると、INSERTを実行し、重複が見つかった場合にスローされたDUP_VAL_ON_INDEX例外をトラップし、元気に進めます:

CREATE TRIGGER updateGuns 
    BEFORE INSERT ON GunsOwned 
    FOR EACH ROW 
BEGIN 
    BEGIN 
    INSERT INTO GUNS 
     (MAKE, MODEL) 
    VALUES 
     VALUES (:NEW.MAKEOWNED, :NEW.MODELOWNED); 
    EXCEPTION 
    WHEN DUP_VAL_ON_INDEX THEN 
     NULL; -- ignore the DUP_VAL_ON_INDEX exception 
    END; 

UPDATE Member 
    SET NumOfGuns = NumOfGuns+1 
    WHERE MemberID = :NEW.OWNERID; 
END UPDATEGUNS; 

個人的に、私は例外を無視して好きではない - しかし、それはあなたの選択だ - 私はむしろ例外を発生しないコードを書くと思います。

幸運のベスト。

関連する問題