如果语句返回多行,SELECT INTO var会做什么?

时间:2015-12-17 12:57:32

标签: sql oracle plsql

鉴于PL / SQL函数看起来有点像:

Function f(pVar IN VARCHAR2) return VARCHAR2 IS
      vs_ret VARCHAR2 := NULL;
    BEGIN
      select name into vs_ret from people where nickname = pVar;
      return vs_ret;
    END f;

如果people.nickname没有唯一性约束,会发生什么?如果(当)两个人有相同的昵称时会发生什么 - 它会导致错误还是只返回语句返回的第一行的值?

这似乎是我正在调整的现有功能,因此选项仅限于更改所有内容。

3 个答案:

答案 0 :(得分:3)

它将抛出预定义的TOO_MANY_ROWSORA-01422)异常。您可以像这样处理异常:

CREATE FUNCTION f(
  pVar IN VARCHAR2
) RETURN VARCHAR2
IS
  vs_ret VARCHAR2;
BEGIN
  SELECT name
  INTO   vs_ret
  FROM   people
  WHERE  nickname = pVar;

  RETURN vs_ret;
EXCEPTION
  WHEN TOO_MANY_ROWS THEN
    RETURN NULL; -- or you could do: RETURN 'Error: Too Many Rows';
  WHEN NO_DATA_FOUND THEN
    RETURN NULL; -- or you could do: RETURN 'Error: Not Found';
END f;

或者,您可以保留未处理的异常;在这种情况下,异常将被传递回调用块的层次结构,并且每个异常将有机会处理它,如果它仍然未处理,将使用ORA-01422: exact fetch returns more than requested number of rows终止查询。

另一种方法是,如果您只想返回第一个名称而不管实际有多少匹配,则将AND ROWNUM = 1添加到WHERE查询的SELECT子句中(这样返回的行永远不会超过一行 - 尽管仍然可以返回零行。

另一种选择,如果你真的想要返回多个值(或没有值),那就是使用BULK COLLECT INTO和一个集合:

CREATE FUNCTION f(
  pVar IN VARCHAR2
) RETURN SYS.ODCIVARCHAR2LIST
IS
  vs_ret SYS.ODCIVARCHAR2LIST;
BEGIN
  SELECT name
  BULK COLLECT INTO vs_ret
  FROM   people
  WHERE  nickname = pVar;

  RETURN vs_ret;
END f;

答案 1 :(得分:0)

不确定这对您是否有用,但在我不关心太多行或没有找到数据的情况下,我将其更改为光标。

在没有数据的情况下发现它没有进入循环,对于太多的行,它只是循环了很多次。

/* Formatted on 12/17/2015 8:18:33 AM (QP5 v5.115.810.9015) */
FUNCTION f (pVar IN VARCHAR2)
   RETURN VARCHAR2
IS
   vs_ret   VARCHAR2 := NULL;
BEGIN
   FOR c IN (SELECT   name
               FROM   people
              WHERE   nickname = pVar)
   LOOP
      vs_ret := c.name;
   END LOOP;

   RETURN vs_ret;
END f;

答案 2 :(得分:0)

如果您在发生错误时知道有意义的事情,您可能会收到错误。

 [echo] abc,123
 [echo] abc,123
 [echo] xyz,678
 [echo] xyz,678
 [echo] ijk,921
 [echo] ijk,921

脚本输出

drop table people;
create table people (name varchar2(200), nickname varchar2(200));
insert into people values('name1','nick1');
insert into people values('name1','nick1');
select * from people;
create or replace function f(pVar IN VARCHAR2) 
return VARCHAR2 
IS
 vs_ret people.name%type;
BEGIN
  select name into vs_ret from people where nickname = pVar;
  return vs_ret;
END f;
select f('nick1') from dual;    
--- ==> error
create or replace function f(pVar IN VARCHAR2) 
return VARCHAR2 
IS
 vs_ret people.name%type;
BEGIN
  select name into vs_ret from people where nickname = pVar;
  return vs_ret;
exception
  when TOO_MANY_ROWS then
    return null; -- This is no good solution but just to demo it
END f;
select f('nick1') from dual;    
-- ==> null as Output
相关问题