In PL/SQL, when you execute a SELECT statement inside a PL/SQL block (such as in a procedure, function, or anonymous block), you must fetch the selected data into variables using the INTO clause.
The error:
PLS-00428: an INTO clause is expected in this SELECT statement
is triggered when PL/SQL expects you to store the result of a SELECT query in a variable, but you forget to include the INTO clause.
1. Why This Error Occurs
In SQL, you can write:
SELECT first_name FROM employees WHERE employee_id = 100;
and it simply displays the result.
But in PL/SQL, you must write:
SELECT first_name INTO v_name FROM employees WHERE employee_id = 100;
because PL/SQL requires a target for the result — a variable to store the value.
2. Example of the Error
Code That Triggers PLS-00428
BEGIN
SELECT first_name FROM employees WHERE employee_id = 100;
END;
/
Error Output
PLS-00428: an INTO clause is expected in this SELECT statement
3. Correct Usage with INTO Clause
Fixed Version
DECLARE
v_name employees.first_name%TYPE;
BEGIN
SELECT first_name INTO v_name FROM employees WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE('Employee name: ' || v_name);
END;
/
Output:
Employee name: Steven
The
INTOclause tells PL/SQL to store the result of the query into the variablev_name.
4. Handling Multiple Columns
If your SELECT returns multiple columns, you need multiple variables in the INTO clause.
Example: Multiple Columns
DECLARE
v_fname employees.first_name%TYPE;
v_lname employees.last_name%TYPE;
BEGIN
SELECT first_name, last_name
INTO v_fname, v_lname
FROM employees
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE('Full Name: ' || v_fname || ' ' || v_lname);
END;
/
5. Using INTO with ROWTYPE
If you’re selecting all columns, you can use %ROWTYPE for cleaner code:
DECLARE
v_emp employees%ROWTYPE;
BEGIN
SELECT * INTO v_emp FROM employees WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE('Employee Email: ' || v_emp.email);
END;
/
6. When You Don’t Need an INTO Clause
The only time you don’t use an INTO clause is when you’re using:
- A cursor FOR loop
- Dynamic SQL with
EXECUTE IMMEDIATE - SELECT INTO as a standalone SQL query (outside PL/SQL)
Cursor FOR Loop Example
BEGIN
FOR rec IN (SELECT employee_id, last_name FROM employees WHERE department_id = 10) LOOP
DBMS_OUTPUT.PUT_LINE(rec.employee_id || ' - ' || rec.last_name);
END LOOP;
END;
/
Notice that there’s no INTO clause here — PL/SQL automatically handles it via the loop variable rec.
7. Common Pitfalls and Fixes
| Mistake | Fix |
|---|---|
Writing SELECT ... alone in PL/SQL | Add INTO clause with variable(s) |
Forgetting INTO for multi-column SELECT | Include all target variables in same order |
Using SELECT in BEGIN...END; block without INTO | Use cursor or dynamic SQL if needed |
| SELECT returns more than one row | Use SELECT INTO only when exactly one row is expected or use CURSOR/LOOP |
8. Summary
PLS-00428 is a very common beginner mistake in PL/SQL programming. To resolve it:
- Always include an
INTOclause when usingSELECTinside PL/SQL blocks. - Ensure the number and type of variables in the
INTOclause match theSELECTlist. - Use
%TYPEand%ROWTYPEto ensure compatibility with column types. - Use cursor loops or collections for multi-row queries.
Want to Avoid This Error Completely?
- Use cursor
FORloops for queries that return multiple rows. - Always test queries in SQL first, then add variables and
INTOclause in PL/SQL. - Add exception handling to capture cases where rows are missing or duplicated.