Skip to content
Oracle Database

Oracle Error ORA-01422

exact fetch returned more than the requested number of rows

Applies to: Oracle Database 19c, 21c, 23ai and 26ai (wording differs: see below)
Last technically reviewed 24 October 2026 on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally
The full message
ORA-01422: exact fetch returned more than the requested number of rows
Other forms of this message
Oracle Database 19c and 21c wording
ORA-01422: exact fetch returns more than requested number of rows
Raised in a stored procedure (with the stack under it)
ORA-01422: exact fetch returned more than the requested number of rows
ORA-06512: at "SHOP.GET_ACTIVE_ADDRESS", line 6
Error code
ORA-01422
Product
Oracle Database
Versions
Oracle Database 19c, 21c, 23ai and 26ai (wording differs: see below)
Last reviewed
24 October 2026

What it means

ORA-01422 means a SELECT INTO (or a DML statement with RETURNING INTO) in PL/SQL returned more than one row, but its target variables can hold only one; PL/SQL raised the predefined exception TOO_MANY_ROWS.

A SELECT ... INTO into scalar variables or a record must return exactly one row. Oracle's current reference lists three causes: a SELECT in exact fetch mode returned more rows than requested (seen from client interfaces), a PL/SQL SELECT INTO returned more than one row, and a PL/SQL UPDATE, DELETE or INSERT ... RETURNING INTO returned more than one row. In PL/SQL this is the predefined exception TOO_MANY_ROWS.

The opposite case, no rows, is ORA-01403 no data found. The current reference's template ends with a placeholder for the number of rows requested; Oracle's documentation does not show how that number is printed, so this page leaves it out. Oracle Database 19c prints the shorter text "exact fetch returns more than requested number of rows".

Common causes

  • The WHERE clause is not on a unique key: a customer can have several addresses, orders or emails, and the code assumed one.
  • Duplicate rows exist where the design assumed uniqueness but no unique constraint enforces it.
  • A join multiplies rows, for example joining to a child table, so one parent row becomes several.
  • An UPDATE or DELETE with RETURNING INTO matches several rows, because its WHERE clause is wider than intended.
  • A filter that used to narrow the result to one row, such as an "active" flag or a date range, now matches more than one.

Diagnose it

Read-only These queries only read the data dictionary (USER_, ALL_ and DBA_ views) and dynamic performance views (V$). They do not change data, privileges or settings, so they are safe to run first. DBA_ and V$ views need the matching privileges.

Run the query and count the rows

SELECT COUNT(*) AS matches
FROM shop.addresses
WHERE customer_id = 4711
  AND is_active = 'Y';
What to look for

Any number above 1 explains the error. Then list the rows to see what makes them different.

Find every key that has more than one row

SELECT customer_id, COUNT(*) AS copies
FROM shop.addresses
WHERE is_active = 'Y'
GROUP BY customer_id
HAVING COUNT(*) > 1
ORDER BY copies DESC;
What to look for

All the keys for which the SELECT INTO would fail, not just the one in the current call.

Is the uniqueness enforced?

SELECT c.constraint_name, c.constraint_type, cc.column_name, cc.position
FROM all_constraints c
JOIN all_cons_columns cc
  ON cc.owner = c.owner AND cc.constraint_name = c.constraint_name
WHERE c.owner = 'SHOP'
  AND c.table_name = 'ADDRESSES'
  AND c.constraint_type IN ('P', 'U')
ORDER BY c.constraint_name, cc.position;
What to look for

The primary and unique keys. If none covers the columns your WHERE clause uses, nothing stops several rows from matching.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Narrow the query to the one row you mean

Changes schema

Add the condition that makes the row unique, such as the primary key or a clear rule for which row wins. FETCH FIRST 1 ROW ONLY with an ORDER BY states that rule explicitly; without the ORDER BY the row chosen is arbitrary.

CREATE OR REPLACE FUNCTION shop.get_active_address (p_customer_id IN NUMBER)
  RETURN shop.addresses.id%TYPE
IS
  v_id shop.addresses.id%TYPE;
BEGIN
  SELECT id INTO v_id
  FROM shop.addresses
  WHERE customer_id = p_customer_id AND is_active = 'Y'
  ORDER BY created_at DESC
  FETCH FIRST 1 ROW ONLY;   -- the newest active address wins
  RETURN v_id;
END;
/

Process all rows with a loop or BULK COLLECT

Changes schema

If several rows are valid, Oracle's action text says to use a FOR loop to process them, or BULK COLLECT to return them into a collection.

CREATE OR REPLACE PROCEDURE shop.verify_active_addresses (p_customer_id IN NUMBER)
IS
  TYPE id_list IS TABLE OF shop.addresses.id%TYPE;
  v_ids id_list;
BEGIN
  SELECT id BULK COLLECT INTO v_ids
  FROM shop.addresses
  WHERE customer_id = p_customer_id AND is_active = 'Y';

  FOR i IN 1 .. v_ids.COUNT LOOP
    shop.verify_address(v_ids(i));
  END LOOP;
END;
/

Enforce the rule with a unique constraint or index

Changes schema

When there really must be only one active row per key, enforce it. A function-based unique index can enforce "one active row per customer" while allowing any number of inactive rows, because rows where the expression is NULL are not indexed. Clean up the existing duplicates first, or creating the index fails.

CREATE UNIQUE INDEX shop.addresses_one_active_ux
  ON shop.addresses (CASE WHEN is_active = 'Y' THEN customer_id END);

Handle TOO_MANY_ROWS only as a clear error

Changes schema

Catching TOO_MANY_ROWS and picking a row silently hides a data problem. If you catch it, raise an application error that names the key, so the duplicates get fixed.

CREATE OR REPLACE FUNCTION shop.get_only_active_address (p_customer_id IN NUMBER)
  RETURN shop.addresses.id%TYPE
IS
  v_id shop.addresses.id%TYPE;
BEGIN
  SELECT id INTO v_id FROM shop.addresses
  WHERE customer_id = p_customer_id AND is_active = 'Y';
  RETURN v_id;
EXCEPTION
  WHEN TOO_MANY_ROWS THEN
    RAISE_APPLICATION_ERROR(-20020,
      'Customer ' || p_customer_id || ' has more than one active address');
END;
/

Examples

A customer with two active addresses

Not reproduced here: no Oracle Database is installed for this site. The message is the current wording from Oracle's error reference, without the row count its template ends with; Oracle Database 19c prints "exact fetch returns more than requested number of rows". Names and the line number are illustrative.

DECLARE
  v_id addresses.id%TYPE;
BEGIN
  SELECT id INTO v_id
  FROM addresses
  WHERE customer_id = 4711 AND is_active = 'Y';   -- two rows match
END;
/
Expected result (documented format, not run)
ORA-01422: exact fetch returned more than the requested number of rows
ORA-06512: at line 4

RETURNING INTO from an UPDATE that matches several rows

Not reproduced here: no Oracle Database is installed for this site. Oracle's current reference names DML RETURNING INTO as one of the causes; the message format is from that reference and the names are illustrative. Use RETURNING BULK COLLECT INTO a collection when several rows are expected.

DECLARE
  v_total orders.total%TYPE;
BEGIN
  UPDATE orders SET total = total * 0.9
  WHERE customer_id = 4711
  RETURNING total INTO v_total;   -- the customer has three orders
END;
/
Expected result (documented format, not run)
ORA-01422: exact fetch returned more than the requested number of rows
ORA-06512: at line 4

How to prevent it

Use SELECT INTO only on a primary or unique key, or with a rule that picks exactly one row (an aggregate, or ORDER BY with FETCH FIRST 1 ROW ONLY). Back every "only one" assumption with a unique constraint or index.

When a query can legitimately return several rows, write it as a cursor loop or BULK COLLECT from the start.

Common questions

How do I fix ORA-01422 exact fetch returns more than requested number of rows?

Run the SELECT INTO's query and count the rows. Then either add the condition that makes it return one row, process all the rows with a loop or BULK COLLECT, or remove the duplicates and add a unique constraint so they cannot come back.

Is ROWNUM = 1 a good fix?

Only if any of the matching rows is acceptable. Without an ORDER BY the row you get is arbitrary and can change, so state which row should win with ORDER BY ... FETCH FIRST 1 ROW ONLY, or fix the duplicates.

Which exception name do I catch for ORA-01422?

TOO_MANY_ROWS, the predefined PL/SQL exception with error code -1422. The no-rows case is NO_DATA_FOUND (ORA-01403).

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally. Messages and explanations follow Oracle's Database Error Messages reference; no Oracle Database was available, so the examples were not run locally.

Still stuck on an Oracle error?

Browse the full Oracle error library, or get hands-on help from an experienced SQL professional.