Oracle’s PL/SQL language has two basic mechanisms for getting data from the database: SELECT and cursors. SELECT is designed to return a single row into local variables; cursors give you the ability to select multiple rows (i.e., a “rowset”) and process them one at a time.

When you use SELECT in a PL/SQL block, it’s important to make sure that exactly one row will always be returned by your query. If more than one row is returned, the TOO_MANY_ROWS exception occurs. Listing A shows an example from Oracle’s HR sample schema: There is more than one employee with the last name King, so the script fails.

DECLARE

   l_employee_last_name         employees.last_name%TYPE;

   l_employee_full_name         VARCHAR2(52);

BEGIN

   l_employee_last_name := 'King';

   SELECT last_name || ', ' || first_name

   INTO l_employee_full_name

   FROM employees

   WHERE last_name = l_employee_last_name;

   DBMS_OUTPUT.PUT_LINE (l_employee_full_name);

END;

/

There are four ways to make sure your code is safe from this error.

  • Select rows using the primary key. In Listing A, I selected by last_name, and it’s quite likely there will be more than one employee with the same last name. If I change the code to select by employee_id instead, I’ll avoid the error because only one row in a table can have the same value in the primary key column(s).
  • Select aggregate functions. By definition, the aggregate functions (AVERAGE, COUNT, MIN, MAX, and SUM) return only one row as a result. Even if its WHERE clause has no matching rows, a COUNT of those rows will return one row — the answer “0.” Selecting the MIN or MAX of a table is frequently done in this way to determine processing limits.
  • Limit the query using ROWNUM. If there is a possibility of returning multiple rows, but any row is as good as any other row, try adding the following condition to the query: AND ROWNUM < 2. This will limit the results to the first row of the set. But remember that it’s the first physical row returned — adding ORDER BY to a query with ROWNUM in it will not give you the highest or lowest row, only the first one.
  • Put the SELECT in its own block. If you surround the SELECT with its own inner block, you can code an exception handler to supply a reasonable value if an error occurs. Listing B shows the previous query enhanced in this way.
DECLARE

   l_employee_last_name         employees.last_name%TYPE;

   l_employee_full_name         VARCHAR2(52);

BEGIN

   l_employee_last_name := 'King';

   BEGIN

      SELECT last_name || ', ' || first_name

      INTO l_employee_full_name

      FROM employees

      WHERE last_name = l_employee_last_name;

   EXCEPTION

      WHEN NO_DATA_FOUND THEN

         l_employee_full_name := '(not on file)';

      WHEN TOO_MANY_ROWS THEN

         l_employee_full_name := '(duplicate name)';

   END;

   DBMS_OUTPUT.PUT_LINE (l_employee_full_name);

END;

/

Bob Watkins (OCP, MCITP, MCDBA, MCT) is a computer professional with 25 years of experience as a technical trainer, consultant, and database administrator. He is a Senior Consultant and Managing Partner at B. Watkins, a database consulting and training firm in the Dallas / Fort Worth area. Visit Bob’s site.

——————————————————————————————

Get Oracle tips in your inbox

TechRepublic’s free Oracle newsletter, delivered each Wednesday, covers automating Oracle utilities, generating database alerts, solving directed graph problems, and more. Automatically subscribe today!

Subscribe to the Data Insider Newsletter

Learn the latest news and best practices about data science, big data analytics, artificial intelligence, data security, and more. Delivered Mondays and Thursdays

Subscribe to the Data Insider Newsletter

Learn the latest news and best practices about data science, big data analytics, artificial intelligence, data security, and more. Delivered Mondays and Thursdays