I faced this problem while developing a Trigger in Oracle: ORA-01403: no data found. I did some research and understood the root of the problem. Nevertheless handling the error exception prevents the above error, but does not solve my problem.
What I am currently looking for is an optimal workaround to perform the lesser query amount/achieve the best performance as possible. I'll try to describe the scenario creating simple examples to the real structure.
I have a "date reference" table to establish periods of time, say:
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)
);
When the trigger is triggered, I'll have one DATE
field - say DATE_GIVEN
(for example sake). What I need is:
DATE_REFERENCE
row in which DATE_GIVEN BETWEEN DATE_START AND DATE_END
(easy); OR
DATE_START
to DATE_GIVEN
.In both cases, I need to retrieve the row with all columns from table DATE_REFERENCE
, no matter if it matches Opt 1 or 2. That's exactly where I faced the problem described.
I wrote this test block to test and try to find a solution. The example below is not working, I know; but it is exactly what I want to accomplish (in concept). I have added comments like -- Lots of code
to make clear that will be part of a more elaborate trigger:
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;
Knowing that the above PL/SQL block is more of a concept than working code, what is the best way to get RESULTROW
populated, minding performance and the lesser queries as possible?
Sorry for the long question, but I figured scenario explanation was necessary. Thanks in advance for any help/thoughts!
Answer: To prevent the PLSQL code from dropping to the exception code when a record is not found, you'll have to perform a count first to determine the number of records that will be returned. For example: -- Check to make sure that at least one record is returned SELECT COUNT(1) INTO v_count FROM sales.
The SELECT INTO statement does not accept an empty result set. To avoid a no data found exception being thrown when a result set is empty, this condition should be handled by either an exit handler, an emptiness check, or by assigning default values.
Declare a new EXCEPTION in the declarations section, perhaps call it NAME_IS_NULL. In the loop body, check to see if the EMP_NAME is NULL (before the INSERT statement). If it is, throw the NAME_IS_NULL exception.
There are 3 ways to resolve Ora-06512: Fix the error causing the unhandled error. Write an exception handler for the unhandled error. Contact the database administrator (DBA).
Just populate the field directly, using ordering and 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;
This will populate the information with one query.
EDIT:
If you want to put a condition in the subquery, it needs to be:
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;
I believe the right condition is DATE_GIVEN <= DATE_END
. This covers both the between
condition and should imply DATE_GIVEN < DATE_START
. This assumes that DATE_END
is never NULL
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With