2017-10-26 17 views
0

学校の割り当て、データベースの作成に取り組んでいます。私のデータベースは写真ビジネスをモデル化しています。そのほとんどはシンプルですが、今は私が立ち往生しています。私のモデルでは、私はPhotography_Availability Entity(Ph_Av)を持っています。そして、写真家が予定されているか利用できないときはいつでも、写真家が利用できない日付と時間間隔(Available_Date、Start_Time_Available、Fin_Time_Available)これらはすべて私のOracleモデラー内のDateTimeデータ型です。誰かが撮影者をスケジュールしようとするたびに、使用可能かどうかをチェックするトリガーを実装したいと考えています(適切な日付と時間間隔で)。ここに私のコードは次のとおりです。私が欲しいの基本的なロジックは、カメラマンはすでに3から午後5時までの間にスケジュールされていて、誰かが2と午後4時の間で、同じ写真家のスケジュールを設定しようと言う、ということであるOracleトリガ:どのように実装するのですか?

CREATE OR REPLACE TRIGGER SAFE_SCHEDULE 
BEFORE INSERT OR UPDATE ON PH_AV 
FOR EACH ROW 
DECLARE 
    ID VARCHAR(20) := NULL; 
    AV_DATE DATE := NULL; 
    START_TIME DATE := NULL; 
    FIN_TIME DATE := NULL; 
BEGIN 
    SELECT PHOTOGRAPHER_ID INTO ID FROM PH_AV WHERE PHOTOGRAPHER_ID = :NEW.PHOTOGRAPHER_ID ; 

    SELECT AVAILABILITY_DATE INTO AV_DATE FROM PH_AV WHERE PHOTOGRAPHER_ID = :NEW.PHOTOGRAPHER_ID; 

    SELECT START_TIME_AVAIL INTO START_TIME FROM PH_AV WHERE PHOTOGRAPHER_ID = :NEW.PHOTOGRAPHER_ID; 

    SELECT FIN_TIME_AVAIL INTO FIN_TIME FROM PH_AV WHERE PHOTOGRAPHER_ID = :NEW.PHOTOGRAPHER_ID; 

    IF ((:NEW.START_TIME_AVAIL >= START_TIME AND :NEW.START_TIME_AVAIL <= FIN_TIME) 
    OR (:NEW.FIN_TIME_AVAIL >= START_TIME AND :NEW.FIN_TIME_AVAIL <= FIN_TIME) 
    OR (:NEW.START_TIME_AVAIL <= START_TIME AND :NEW.FIN_TIME_AVAIL >= FIN_TIME)) 
     THEN 
     DBMS_OUTPUT.PUT_LINE('Cannot be scheduled, photographer unavailable'); 
    ELSE 
    DBMS_OUTPUT.PUT_LINE('PHOTOGRAPHER SUCCESSFULLY SCHEDULED'); 
    END IF; 
    EXCEPTION 
     WHEN NO_DATA_FOUND THEN 
      DBMS_OUTPUT.PUT_LINE('NO DATA FOUND'); 
     WHEN OTHERS THEN 
      DBMS_OUTPUT.PUT_LINE('ERROR-' || SQLERRM); 
END; 
/

、明らかにこれは衝突します。 Myのifステートメントは、新しい挿入された値が予定されている値と衝突するかどうかをチェックします。今、私がこれを実行した後、Script Outputはエラーがあると述べません。しかし、私のメッセージログにはかなりの数のクレームがあります(そのほとんどは(内部エラー)No Throwable Stack Elementでnullです)。

これは私の初めてのトリガを実装したもので、宣言された変数のDateデータ型と思われるかもしれませんが、私は迷っています。助言がありますか?エントリ内の重複を防ぐために、次のと要件として、私は次のようなものだろう、簡単な構造で

+0

あなたのタイトルを編集しました:SQLは "続編"とは言えませんが、もっと重要なことに、トリガーはSQL \ * Plusとほとんど関係ありません。質問はOracleトリガーに関するものです。 – mathguy

+2

無関係ですが、同じテーブルから4つの異なる列を読み取るのに4つの選択肢は必要ありません。あなたのケースでは、何も選択する必要はありません。 ':PHOTOGRAPHER_ID =:NEW.PHOTOGRAPHER_ID'を使って、あなたが望む情報を既に含んでいるだけです。 –

+0

「PH_AVを記述する」を追加することをお勧めします。列の種類を参照してください。エラー出力のログが表示されていることを示すのに役立ちます。 – slashlos

答えて

1

AVAIL:代わりに、テーブルからデータを取得する

CREATE SEQUENCE avail_sq; 

CREATE TABLE avail 
(
    avail_id INTEGER, 
    person_id INTEGER, 
    start_dtm DATE, 
    end_dtm DATE 
); 

CREATE OR REPLACE TRIGGER test_avail_trg 
FOR INSERT OR UPDATE ON avail 
COMPOUND TRIGGER 
    TYPE avail_tt IS TABLE OF avail%ROWTYPE; 

    avail_t avail_tt := avail_tt(); 
    l_cnt INTEGER; 

    BEFORE EACH ROW IS 
    BEGIN 
     avail_t.EXTEND; 
     avail_t(avail_t.COUNT).avail_id := :new.avail_id; 
     avail_t(avail_t.COUNT).person_id := :new.person_id; 
     avail_t(avail_t.COUNT).start_dtm := :new.start_dtm; 
     avail_t(avail_t.COUNT).end_dtm := :new.end_dtm; 
    END BEFORE EACH ROW; 

    AFTER STATEMENT IS 
    BEGIN 
     FOR i IN avail_t.FIRST..avail_t.LAST LOOP 
     SELECT COUNT(*) 
      INTO l_cnt 
      FROM avail a 
      WHERE a.person_id = avail_t(i).person_id 
      AND ((a.start_dtm <= avail_t(i).start_dtm AND a.end_dtm > avail_t(i).start_dtm) OR 
       (a.start_dtm > avail_t(i).start_dtm AND a.start_dtm < avail_t(i).end_dtm)) 
      AND a.avail_id != avail_t(i).avail_id; -- Can't overlap itself 

     IF l_cnt > 0 THEN 
      raise_application_error(-20000, 'Overlap detected'); 
     END IF; 
     END LOOP; 
    END AFTER STATEMENT; 
END; 
/

を、私は存在チェックの多くをやっています。 2つの日付/時刻フィルタは、任意のポイントで重複するエントリをチェックします。最初は、新しい行と同じかそれ以前と同時に開始する既存のエントリをチェックし、新しい行の開始後に終了します。 2番目の行は、新しい行の後に始まり、新しい行が終了する前に開始する既存のエントリをチェックします。

これらのフィールドの更新も許可するため、COMPOUND TRIGGERを使用する必要があります。これにより、各行に必要なデータを収集することができます。また、ステートメントが完了し、突然変異が行われた後に処理できます。

+2

これはUPDATEにはうまくいかないでしょうか?更新中のテーブルから選択すると、「突然変異」エラーが発生します。 – kfinity

+0

あなたは私がオリジナルの質問を読んだとき、私は 'UPDATE'の要件を逃しました。その懸念に対処するために「COMPOUND TRIGGER」で更新されました。 –

+0

ええ、私はちょうど突然変異の問題に遭遇しました。基本的に、私は読んでいるテーブルを変更するためにトリガーを使うことはできません。しかし、私はあなたの考えが気に入っていますが、私はそのほとんどを理解していません(最初の学期はオラクルとやりとりしています)。私はこれが私が制約で扱わなければならないものだと考えています。私が見つけたら解決策を投稿します – Breeduss

関連する問題