テーブルにデータを挿入しようとすると、一意キーの違反や外部キーの違反など、さまざまな理由で失敗する可能性があります。
DUP_VAL_ON_INDEX 例外を使用して、一意のキーが違反していることを知ることができますが、一意のマークが付いた列が複数ある場合、どのキーを知ることができますか? この場合、トリガーを使用する必要がありますか?
(挿入されるデータが正常であることを確認するためにテーブルを照会する代わりに、例外を使用してストアド プロシージャのフローを駆動しています。)
テーブルにデータを挿入しようとすると、一意キーの違反や外部キーの違反など、さまざまな理由で失敗する可能性があります。
DUP_VAL_ON_INDEX 例外を使用して、一意のキーが違反していることを知ることができますが、一意のマークが付いた列が複数ある場合、どのキーを知ることができますか? この場合、トリガーを使用する必要がありますか?
(挿入されるデータが正常であることを確認するためにテーブルを照会する代わりに、例外を使用してストアド プロシージャのフローを駆動しています。)
それだけの価値があるため、一意性を強制するためにアプリケーション コードだけに頼らないことをお勧めします。1 つの主な (しゃれが意図された) 理由は、特にデータが複数のトランザクションで同時に挿入または更新される場合に、これを正しく行うコードを記述するのが難しいことです。データベースが正しく効率的に適用する一意の制約を宣言するのは比較的簡単です。
どの列が一意の制約に違反しているかを知りたい場合、1 つのアプローチ (そして、それが「かなり」ではないことに気づきました) は次のとおりです。
SQLERRM
ます)。どの行が一意の制約に違反しているかを知りたい場合は、この例LOG ERRORS INTO
で説明されているように、ステートメントの句を使用しINSERT
て、問題のある行をエラー ログ テーブルに記録できます。
一意の制約に違反した行と列を知りたい場合は、両方の方法を組み合わせることができます。LOG ERRORS INTO
句を使用して行をログに記録し、エラー メッセージから定数名を解析します (エラー ログにも記録されます)。表) を参照して、対応する列を検索します。
そうは言っても、必ずしも次のいずれかを選択する必要はありません: a) 最初にデータをチェックし、チェックに合格した場合にのみ挿入するか、b) データを挿入しようとしてから、エラーを報告および/または処理します。
これはトリガーの目的ではありません。トリガー内でターゲット テーブルをクエリできないため、一意性違反を実際にチェックできないことに注意してください。トリガーの最善の理由は、シーケンスの ID など、行に既定のデータが入力されていることを確認することだと思います。挿入された行がステートメントと異なる理由が明確でないため、トリガーもコードを難読化します。
制約は、明白な機能以外にも便利な機能を実行します。オプティマイザは、制約内の情報を使用して実行計画を判断できます。たとえば、列が NOT NULL であるかどうかをオプティマイザが認識している場合、より効率的なルートを計算できます。
上記のINSERT
@Benによって与えられたステートメントは良いものです.匿名ブロック内にステートメントをラップすることもできます:
BEGIN
... application code ...
BEGIN
INSERT INTO mytable (col1, col2) VALUES (val1, val2);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
... error handling code ...
END;
... application continues...
END;
(制約からの) 例外またはトリガー? 私はどちらとも言いません。
トリガーや制約ではなく、アプリケーション コードとクエリを使用してアプリケーションのロジックを駆動することを強くお勧めします。ロジックをエラー状態の処理から分離すると、コードの動作が魔法のように見えるだけです。
制約はバックアップ プランとして非常に役立ちますが (アプリケーション ロジックのエラーまたは変更の場合)、実行時エラー処理を希望どおりに支援しないという点で正しいです (つまり、重複したキーを公開するのに役立ちません)。使用しようとしたINSERT
ステートメント)。
間違いなく決定したように、トリガーを使用して説明したことを非常に簡単に実行できますが、最終的には、同じ論理テスト (「このレコードは既に存在しますか?」) をトリガーに隠しているだけです。INSERT
ステートメントが存在するアプリケーションコードとは対照的です。テーブルに複数のトリガーが存在する場合、それらを不必要に実行するオーバーヘッドが発生する可能性があります。たとえば、1 つがエラーを発生させた場合、最初に実行された他のトリガーは無駄でした。
新しいステートメントを実行する前にデータの状態を事前チェックするために追加のステートメントを書きたくない場合はINSERT
、次のようなものを使用することをお勧めします。
INSERT INTO my_table (col1, col2)
SELECT l_val1, l_val2
FROM dual
WHERE NOT EXISTS (
SELECT 1
FROM my_table t
WHERE t.col1 = l_val1
AND t.col2 = l_val2
)
SQL%ROWCOUNT
少なくとも、キーに違反することはありませんが、 0 (行が挿入されていないため、既に存在している必要があります) か 1かをテストすることで、行が既に存在するかどうかがわかります。
ただし、これでもキー違反の値は得られません。クエリを作成して、制約に違反するものを見つける必要があります。