SELECT INTO 语句是 SQL SELECT 命令的 SPL 变体。

SELECT INTO与SQL SELECT区别如下:

  • 该 SELECTINTO 旨在将结果赋给变量或记录,然后它们可以在 SPL 程序语句中使用。
  • SELECT INTO 的可访问结果集最多是一行。

除了上述的以外,SELECT 命令的所有子句(如 WHERE、ORDER BY、GROUPBY、HAVING 等)都对 SELECTINTO 有效。以下是 SELECT INTO 的两个变体。

SELECT select_expressions INTO target FROM ...;

target 是简单变量的逗号分隔列表。select_expressions 和语句的其余部分与 SELECT 命令相同。所选值必须在数据类型、数量和顺序方面与目标的结构完全匹配,否则会发生运行时错误。

SELECT * INTO record FROM table ...;

record 是以前声明的记录变量。

如果查询返回零行,会将 null 值赋给目标。如果查询返回多行,会将第一行赋给目标并丢弃其余部分。(请注意,“第一行”定义不明确,除非您使用 ORDER BY。)

说明 如果未返回一行或返回了多行,SPL 会引发异常。

有一个使用 BULKCOLLECT 子句的 SELECT INTO 变体,它允许包含返回到集合中的多行的结果集。

您可以在 EXCEPTION 块中使用 WHEN NO_DATA_FOUND 子句来确定赋值是否成功(也就是说,查询至少返回了一行)。

此版本的 emp_sal_query 存储过程使用将结果集返回到记录中的 SELECT INTO 变体。还请注意,添加了包含 WHENNO_DATA_FOUND 条件表达式的 EXCEPTION 块。

CREATE OR REPLACE PROCEDURE emp_sal_query (
    p_empno         IN emp.empno%TYPE
)
IS
    r_emp           emp%ROWTYPE;
    v_avgsal        emp.sal%TYPE;
BEGIN
    SELECT * INTO r_emp
        FROM emp WHERE empno = p_empno;
    DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
    DBMS_OUTPUT.PUT_LINE('Name       : ' || r_emp.ename);
    DBMS_OUTPUT.PUT_LINE('Job        : ' || r_emp.job);
    DBMS_OUTPUT.PUT_LINE('Hire Date  : ' || r_emp.hiredate);
    DBMS_OUTPUT.PUT_LINE('Salary     : ' || r_emp.sal);
    DBMS_OUTPUT.PUT_LINE('Dept #     : ' || r_emp.deptno);

    SELECT AVG(sal) INTO v_avgsal
        FROM emp WHERE deptno = r_emp.deptno;
    IF r_emp.sal > v_avgsal THEN
        DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
            || 'department average of ' || v_avgsal);
    ELSE
        DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
            || 'department average of ' || v_avgsal);
    END IF;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        DBMS_OUTPUT.PUT_LINE('Employee # ' || p_empno || ' not found');
END;

如果使用不存在的员工编号执行查询,结果显示如下。

EXEC emp_sal_query(0);

Employee # 0 not found

具有 SELECT INTO 的 EXCEPTION 部分中使用的另一个条件子句是 TOO_MANY_ROWS 异常。如果 SELECT INTO 语句选择了多行,则 SPL 会引发异常。

在执行以下块时,会引发 TOO_MANY_ROWS 异常,因为指定的部门中有许多员工。

DECLARE
    v_ename         emp.ename%TYPE;
BEGIN
    SELECT ename INTO v_ename FROM emp WHERE deptno = 20 ORDER BY ename;
EXCEPTION
    WHEN TOO_MANY_ROWS THEN
        DBMS_OUTPUT.PUT_LINE('More than one employee found');
        DBMS_OUTPUT.PUT_LINE('First employee returned is ' || v_ename);
END;

More than one employee found
First employee returned is ADAMS