SQL%FOUND 对游标结果没有反应

SQL%FOUND not reacting to cursor results

需要写一个程序,输入country_id,return那个国家的所有部门,如果找到none,它必须return "none found in country + country_id"(我的 return 字符串将是荷兰语),我得到了大部分代码只是 sql%found 没有像我想象的那样与光标交互,我想知道是什么原因这个。

尝试将 = TRUE 更改为 != TRUE,仍然给我输出,就好像 sql%found 是 false

CREATE OR REPLACE PROCEDURE country_dept
    (p_land_id    IN    countries.country_id%TYPE)
AS
BEGIN
    FOR REC IN 
(
    SELECT department_name
        FROM departments
    WHERE location_id IN 
        (
        SELECT location_Id
            FROM locations
            WHERE country_id IN 
            (
            SELECT country_id
                FROM countries
                WHERE country_id = p_land_id
            )
        )
)

        LOOP
        IF SQL%FOUND = TRUE THEN
            DBMS_OUTPUT.PUT_LINE(rec.department_name);      
        ELSE
        DBMS_OUTPUT.PUT_LINE('Er zijn geen departementen gevestigd in het land met id ' || p_land_id);
    END IF;
END;
/

我找到了这个解决方案,但它很糟糕

CREATE OR REPLACE PROCEDURE country_dept
    (p_land_id    IN    countries.country_id%TYPE)
AS
    v_number NUMBER :=0;
BEGIN
    FOR REC IN 
(
    SELECT department_name
        FROM departments
    WHERE location_id IN 
        (
        SELECT location_Id
            FROM locations
            WHERE country_id IN 
            (
            SELECT country_id
                FROM countries
                WHERE country_id = p_land_id
            )
        )
)
        LOOP
            DBMS_OUTPUT.PUT_LINE(rec.department_name);
            v_number := 1;
        END LOOP;
        IF v_number != 1 THEN       
            DBMS_OUTPUT.PUT_LINE('Er zijn geen departementen gevestigd in thet land met id ' || p_land_id);
        END IF;
END;
/

您的解决方案是正确的,原因如下:

游标循环是一种打开游标并自动关闭游标的简便方法,无需检查是否找到值。在循环范围内,记录始终存在。

因此,我们最终会做这样的事情:

CREATE OR REPLACE PROCEDURE country_dept
    (p_land_id    IN    countries.country_id%TYPE)
AS
    found BOOLEAN := false; -- Note use of BOOLEAN
BEGIN
    FOR REC IN 
(
    SELECT department_name
        FROM departments
    WHERE location_id IN 
        (
        SELECT location_Id
            FROM locations
            WHERE country_id IN 
            (
            SELECT country_id
                FROM countries
                WHERE country_id = p_land_id
            )
        )
)
        LOOP
            DBMS_OUTPUT.PUT_LINE(rec.department_name);
            found := true;
        END LOOP;
        IF not found THEN       
            DBMS_OUTPUT.PUT_LINE('Er zijn geen departementen gevestigd in thet land met id ' || p_land_id);
        END IF;
END;
/

注意使用布尔值而不是数字标志。 此外,我假设您将把它变成一个函数并以某种方式得到 return 的结果,而不是使用 DBMS_OUTPUT... 尽管有很多使用 DBMS_OUTPUT 的生产应用程序。

现在,不使用游标循环的替代方法是这样的:

declare
  cursor c is select 'Hello World!' as phrase from dual where 1=2;
  v_phrase varchar2(100);
begin
  open c;
  fetch c into v_phrase;
  if c%NOTFOUND then
    v_phrase := 'Not found!';
  end if;
  close c;
  dbms_output.put_line(v_phrase);
end;
/

在这种情况下,我们显式打开游标,获取,然后检查是否找到了某些东西。

我们也必须明确关闭游标。如果我们期望多个值,那么我们需要将所有内容包装在一个循环中并在某处添加一个 EXIT WHEN c%NOTFOUND 。总而言之,它很讨厌。

两者都不是很漂亮,但我会使用游标循环和布尔标志,因为它避免了使用显式游标时所需的手动操作。