J'ai rencontré ce problème lors du développement d'un déclencheur dans Oracle: ORA-01403: aucune donnée trouvée . J'ai fait des recherches et j'ai compris la racine du problème. Néanmoins le traitement de l'exception d'erreur empêche l'erreur ci-dessus, mais ne résout pas mon problème.
Ce que je recherche actuellement, c’est une solution de contournement optimale pour effectuer le moins de requêtes possible et obtenir les meilleures performances possibles. Je vais essayer de décrire le scénario en créant des exemples simples à la structure réelle.
J'ai un tableau "date référence" pour établir des périodes de temps, disons:
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)
);
Lorsque le déclencheur est déclenché, j'aurai un champ DATE
- disons DATE_GIVEN
(par exemple sake). Ce dont j'ai besoin c'est:
DATE_REFERENCE
dans laquelle DATE_GIVEN BETWEEN DATE_START AND DATE_END
(facile); OUDATE_START
le plus proche à DATE_GIVEN
.Dans les deux cas, j'ai besoin de récupérer la ligne avec toutes les colonnes de la table DATE_REFERENCE
, peu importe si elle correspond à Opt 1 ou 2. C'est exactement là où j'ai rencontré le problème décrit.
J'ai écrit ce bloc de test à test et essayer de trouver une solution. L'exemple ci-dessous ne fonctionne pas , je sais; mais c’est exactement ce que je veux accomplir (dans le concept). J'ai ajouté des commentaires comme -- Lots of code
pour préciser que cela fera partie d'un déclencheur plus élaboré:
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;
Sachant que le bloc PL/SQL ci-dessus est davantage unconceptquecode de travail, quel est le meilleur moyen de remplir RESULTROW
, en tenant compte des performances et des petites requêtes possibles?
Désolé pour la longue question, mais j'ai pensé qu'une explication de scénario était nécessaire. Merci d'avance pour toute aide/pensées!
Remplissez simplement le champ directement, en utilisant ordering et 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;
Cela va remplir les informations avec une requête.
MODIFIER:
Si vous voulez mettre une condition dans la sous-requête, elle doit être:
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;
Je crois que la bonne condition est DATE_GIVEN <= DATE_END
. Cela couvre à la fois la condition between
et devrait impliquer DATE_GIVEN < DATE_START
. Cela suppose que DATE_END
n'est jamais NULL
.
J'ai aussi eu le même problème, résolu comme ça:
si la ligne n'existe pas dans la table LADDER.INCR_PROCESS
, IsPassed
devient 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;