2012-01-19 9 views
0

私はSQLの初心者です。日付をSQLの ":new"テーブルと比較する

私はSQLでトリガーを作成しようとしています。

select brw.borage, bt.agelower, bt.ageupper 
into borage, minage, maxage 
from borrower brw 
    inner join loan ln on ln.borid = brw.borid 
    inner join bookcopy bc on ln.bcid = bc.bcid 
    inner join booktitle bt on bt.isbn = bc.isbn 
where ln.bcid = :new.bcid 
and ln.borid = :new.borid; 
-- and ln.dateout = :new.dateout; 

ローンテーブルの主キーが「BCID」、「borID」と「dateOut」で構成されています。このコードは、私に迷惑を与えています。 最後の行をコメントアウトすると、新しく追加された行がテーブルに追加されます。 最後の行のコメントを外しても機能しません!

私はちょうど(非コメント行で)このエラーが出る:

Row 34: ORA-01403: no data found 
ORA-01403: no data found 

意味オラクルは、クエリ条件に一致するすべての行を見つけることができませんでした。

注:私は行のコメントを外すとき、私はまた、上のセミコロンを削除します。

+0

このトリガーはどのテーブルに定義されていますか? 'DATEOUT'は(おそらく異なる)トリガーで定義されていますか? –

+0

@JustinCaveトリガーは "Loan"テーブルで定義されています。 DateOutはloansテーブルの日付フィールドです。私が持っている唯一のトリガは、私が今作成しようとしているトリガです、それは上に作成または置き換えています:)それは割り当ての一部であるので、私はすべてのコードを投稿しないようにしています。慎重に編集せずに投稿した場合は、私自身の仕事のために盗作されてしまいます。 – David

+0

@JustinCave DateOutは定義されておらず、どこでも宣言されていませんが、Loansテーブルの一部です。私はそれを何か宣言すべきか? – David

答えて

4

OKのように見えます。最初に、テーブルAの行レベルのトリガーはテーブルAを照会すべきではありません。一般的にそうすることで、「ORA-04091:表が突然変異しています」というエラーが生成されます。トリガーがLOANに定義されているため、クエリはLOANテーブルを参照するべきではありません。 :NEWレコード内の現在の行のデータのみを参照する必要があります。ケースである、あなたはおそらく「あなたは2つのクエリを組み合わせることができ

select brw.borage 
    into borage 
    from borrower brw 
where brw.borid = :new.borid; 

select bt.agelower, bt.ageupper 
    into minage, maxage 
    from bookcopy bc on :new.bcid = bc.bcid 
     inner join booktitle bt on bt.isbn = bc.isbn; 

が、私はドン(私はここでは、テーブル間の関係のカーディナリティについて推測していることに注意してください)このような何かをしたいということ

結果をより複雑にすることなく、簡単に行うことができます。

さらに、データベース内の列の名前を共有するローカル変数(たとえば、borage)を使用しないようにする必要があります。それは、困惑するスコープ解決バグを生成する傾向があります。例えば、SCOTT.EMPテーブルを使用して

何の従業員がEMPNO -17

SQL> select count(*) 
    2 from emp 
    3 where empno = -17; 

    COUNT(*) 
---------- 
     0 

のしかしではありません私はEMPNOのを従業員の数をカウントしようと、単純なPL/SQLブロックを書くとき-17、得られる結果は14です。あなたはバグを見つけられますか?

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 empno integer := -17; 
    3 cnt integer; 
    4 begin 
    5 select count(*) 
    6  into cnt 
    7  from emp e 
    8  where e.empno = empno; 
    9 dbms_output.put_line(cnt); 
10* end; 
SQL>/
14 

PL/SQL procedure successfully completed. 

問題は、私はe.empno = empnoを書いたとき、私は明らかにローカル変数を参照するEMPテーブルおよび式の右辺にEMPNO列を参照する式の左辺を意図していることですEMPNO。しかし残念なことに私の場合、Oracleはテーブルの列に最初に非修飾のEMPNOを解決し、その後は同じ名前のローカル変数に解決します。名前付きPL/SQLブロックを使用している場合は、ブロックの名前をローカル変数の別名として使用して対処できますが、事実上誰もそれを実行しません。

これらの問題を回避するために、ほとんどの開発者は変数名にある種の接頭辞を使用します。たとえば、パラメータ名の接頭辞としてP_、ローカル変数の接頭辞としてL_、パッケージのグローバル変数の接頭辞としてG_を使用します。これは比較的一般的な規則ですが、他の規則も存在します。重要なのは、同じ名前を使用するローカル変数と列名を決して持たないようにするための方法があることです。

0

あなたはこのエラーを無視して、トリガーの実行を継続する必要がある場合は、あなただけ

exception 
    WHEN NO_DATA_FOUND THEN 
    NULL 

を追加することができますので、あなたのトリガーの本体は

begin 
    select brw.borage, bt.agelower, bt.ageupper 
    into borage, minage, maxage 
    from borrower brw 
    inner join loan ln on ln.borid = brw.borid 
    inner join bookcopy bc on ln.bcid = bc.bcid 
    inner join booktitle bt on bt.isbn = bc.isbn 
    where ln.bcid = :new.bcid 
    and ln.borid = :new.borid; 
    and ln.dateout = :new.dateout; 
    // other actions 

    exception 
    WHEN NO_DATA_FOUND THEN 
    NULL 
end; 
+1

私は残念ながら、エラーを無視したくない:/ – David