SELECT INTO语句是SQL SELECT命令的SPL变体。
SELECT INTO与SQL SELECT区别如下:
SELECT INTO旨在将结果赋给变量或记录,可以在SPL程序语句中使用。
SELECT INTO的可访问结果集最多是一行。
除了上述之外,SELECT命令的所有子句(如WHERE、ORDER BY、GROUPBY、HAVING等)都对SELECT INTO有效。以下是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。
CREATE TABLE emp ( empno NUMBER(4) NOT NULL CONSTRAINT emp_pk PRIMARY KEY, ename VARCHAR2(10), job VARCHAR2(9), mgr NUMBER(4), hiredate DATE, sal NUMBER(7,2) CONSTRAINT emp_sal_ck CHECK (sal > 0), comm NUMBER(7,2), deptno NUMBER(2) ); INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20); INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30); INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,'22-FEB-81',1250,500,30); INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,'02-APR-81',2975,NULL,20); INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250,1400,30);
执行如下语句,创建emp_sal_query存储过程,使用将结果集返回到记录中的SELECT INTO变体,添加了包含WHEN NO_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语句选择了多行,则引发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 JONES