WHILE循环出错:ORA-01422:精确提取返回的请求行数多于请求的行数

问题描述 投票:0回答:1

我是PL / SQL的新手。我想使用WHILE循环显示COUNTRIES表中country_id和country_name值的country_id,其值范围从51到55。循环将在55完成并显示5个国家。

我得到这个错误。我无法弄清楚出了什么问题。

DECLARE
    v_country_id countries.country_id%TYPE;
    v_country_name countries.country_name%TYPE;
    v_counter NUMBER := 51;
BEGIN
    SELECT country_id, country_name INTO v_country_id, v_country_name
    FROM countries;

    WHILE v_counter <= 55 LOOP
        DBMS_OUTPUT.PUT_LINE (v_counter ||' is : '|| v_country_id|| 'Country name is '||v_country_name);
        v_counter := v_counter+1;
    END LOOP;
END;
sql oracle plsql
1个回答
2
投票

您的v_country_idv_country_name变量一次只能包含一个值,对应于一个国家/地区。您试图将所有国家/地区的值选择为这些标量变量,这是造成错误的原因。

您可以使用a cursor for-loop,其中光标查询根据ID范围选择您感兴趣的五个国家/地区:

BEGIN
  FOR r_country IN (
    SELECT country_id, country_name
    FROM countries
    WHERE country_id BETWEEN 51 AND 55
    ORDER BY country_id
  )
  LOOP
    DBMS_OUTPUT.PUT_LINE ('Country ' || r_country.country_id
      || ' is ' || r_country.country_name);
  END LOOP;
END;
/

您还可以选择包含具有这些字段的记录的集合,并在集合上循环以显示输出 - 在填充集合时过滤行,或者在循环时对其进行循环。

使用dbms_output除了调试之外的任何事情都不是一个好主意,因为它依赖于客户端能够显示它,这并非总是如此。

你当然不需要PL / SQL,你可以自己运行游标查询,但可能这是一个练习......

SELECT 'Country ' || country_id || ' is ' || country_name
FROM countries
WHERE country_id BETWEEN 51 AND 55
ORDER BY country_id;

如果您真的想使用while循环,可以使用显式游标:

DECLARE
  v_country_id countries.country_id%TYPE;
  v_country_name countries.country_name%TYPE;
  v_counter PLS_INTEGER := 1;

  CURSOR c_country IS
    SELECT country_id, country_name
    FROM countries
    WHERE country_id >= 51
    ORDER BY country_id;
BEGIN
  OPEN c_country;
  WHILE v_counter <= 5
  LOOP
    FETCH c_country INTO v_country_id, v_country_name;
    -- in case there are fewer than 5 to display
    EXIT WHEN c_country%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE (v_counter || ': '
      || 'Country ' || v_country_id || ' is ' || v_country_name);
    v_counter := v_counter + 1;
  END LOOP;
END;
/

或者你可以使用一个集合:

DECLARE
  TYPE t_country_rec IS RECORD (
    country_id countries.country_id%TYPE,
    country_name countries.country_name%TYPE
  );
  TYPE t_country_tab IS TABLE OF t_country_rec;
  v_countries t_country_tab;
  v_counter PLS_INTEGER := 1;
BEGIN
  SELECT country_id, country_name
  BULK COLLECT INTO v_countries
  FROM countries
  WHERE country_id >= 51
  ORDER BY country_id;

  WHILE v_counter <= 5
  LOOP
    DBMS_OUTPUT.PUT_LINE (v_counter || ': '
      || 'Country ' || v_countries(v_counter).country_id
      || ' is ' || v_countries(v_counter).country_name);
    v_counter := v_counter + 1;
  END LOOP;
END;
/

您也可以使用for循环中的任何一个,并且可以跳过查询中的过滤器并在循环中执行此操作。

但隐式游标for循环更简单。


我还没有在大学里学习'光标'

如果您不应该使用游标,那么他们可能希望您在循环内执行单行查询,这样效率较低但更接近原始代码; select ... into在循环内移动,但也得到一个where子句,只获得与当前计数器值匹配的单行:

DECLARE
  v_country_id countries.country_id%TYPE;
  v_country_name countries.country_name%TYPE;
  v_counter NUMBER := 51;
BEGIN
  WHILE v_counter <= 55 LOOP
    SELECT country_id,country_name INTO v_country_id, v_country_name
    FROM countries
    WHERE country_id = v_counter;

    DBMS_OUTPUT.PUT_LINE (v_counter ||' is : '|| v_country_id
      || ' Country name is '||v_country_name);

    v_counter := v_counter+1;
  END LOOP;
END;
/
© www.soinside.com 2019 - 2024. All rights reserved.