Oracleでトリガーを開発中にこの問題に直面しました: ORA-01403:データが見つかりません 。私はいくつかの調査を行い、問題の根本を理解しました。それでも エラー例外の処理 は上記のエラーを防ぎますが、問題を解決しません。
私が現在探しているのは、より少ないクエリ量を実行する/可能な限り最高のパフォーマンスを達成するためのoptimal回避策です。実際の構造に対する簡単な例を作成するシナリオについて説明します。
期間を設定するための「日付参照」テーブルがあります。
CREATE TABLE DATE_REFERENCE (
DATE_START DATE NOT NULL,
DATE_END DATE NOT NULL,
-- Several other columns here, this is just a silly example
CONSTRAINT PK_DATE_REFERENCE PRIMARY KEY(DATE_START, DATE_END)
);
トリガーがトリガーされると、DATE
フィールドが1つあります-DATE_GIVEN
と言います(例:日本酒)。私が必要なのは:
DATE_REFERENCE
行がDATE_GIVEN BETWEEN DATE_START AND DATE_END
(簡単)である行を見つけるには、[〜#〜]または[〜#〜]DATE_START
からDATE_GIVEN
に次に近いものを見つける必要があります。どちらの場合も、オプション1または2と一致するかどうかに関係なく、テーブルDATE_REFERENCE
からすべての列を含む行を取得する必要があります。ここで、説明した問題に直面しました。
このテストブロックをtestに書き込み、解決策を見つけようとしました。下の例は機能していませんです。 しかし、exactly達成したいこと(概念的に)。 -- Lots of code
などのコメントを追加して、より複雑なトリガーの一部になることを明確にしました。
DECLARE
DATE_GIVEN DATE;
RESULTROW DATE_REFERENCE%ROWTYPE;
BEGIN
-- Lots of code
-- Lots of code
-- Lots of code
DATE_GIVEN := TO_DATE('2014-02-26 12:30:00', 'YYYY-MM-DD HH24:MI:SS');
-- This one throws the ORA-01403 exception if no data was found
SELECT
* INTO RESULTROW
FROM
DATE_REFERENCE
WHERE
DATE_GIVEN BETWEEN DATE_START AND DATE_END;
-- If the above didn't throw exceptions, I would continue like so:
IF RESULTROW IS NULL THEN
SELECT
* INTO RESULTROW
FROM
DATE_REFERENCE
WHERE
DATE_START > DATE_GIVEN
AND ROWNUM = 1
ORDER BY DATE_START ASC;
END IF;
-- Now RESULTROW is populated, and the rest of the trigger code gets executed ~beautifully~
-- Lots of code
-- Lots of code
-- Lots of code
END;
上記のPL/SQLブロックはworking codeよりもconceptの方が多いことを知って、 RESULTROW
にデータを取り込むための最良の方法は、パフォーマンスと可能な限り少ないクエリを考慮してですか?
長い質問で申し訳ありませんが、シナリオの説明が必要だと思いました。どんな助け/考えでも前もってありがとう!
順序付けとrownum
を使用して、フィールドに直接入力するだけです。
SELECT * INTO RESULTROW
FROM (SELECT *
FROM DATE_REFERENCE
ORDER BY (CASE WHEN DATE_GIVEN BETWEEN DATE_START AND DATE_END
THEN 1 ELSE 0
END) DESC,
(DATE_START - DATE_GIVEN)
) t
WHERE rownum = 1;
これにより、1つのクエリで情報が入力されます。
編集:
サブクエリに条件を設定する場合は、次のようにする必要があります。
SELECT * INTO RESULTROW
FROM (SELECT *
FROM DATE_REFERENCE
WHERE DATE_GIVEN <= DATE_END
ORDER BY (CASE WHEN DATE_GIVEN BETWEEN DATE_START AND DATE_END
THEN 1 ELSE 0
END) DESC,
(DATE_START - DATE_GIVEN)
) t
WHERE rownum = 1;
適切な状態はDATE_GIVEN <= DATE_END
だと思います。これはbetween
条件の両方をカバーし、DATE_GIVEN < DATE_START
を意味するはずです。これは、DATE_END
がNULL
ではないことを前提としています。
私も同様の問題があり、次のように解決しました:
行がテーブルLADDER.INCR_PROCESS
に存在しない場合、IsPassed
はNullとして取得されます。
Declare
IsPassed Integer ;
Begin
Select I.LVL Into IsPassed
From LADDER.INCR_PROCESS I
Right
Join Dual on I.LVL >= 90010 and I.Passed = 0
Where RowNum = 1 ;
....
End;