SQL%未找到问题

时间:2018-10-31 05:28:18

标签: plsql oracle11g

当我执行以下代码时,它不会为deptno = 40打印消息“雇员不存在,部门编号不存在”。

declare
    Cursor c1 is select * from dept;
    Cursor c2(p_deptno number) is select * from emp where deptno=p_deptno;
Begin
    For i in c1
    Loop
        for j in c2(i.deptno)
        loop    
            if sql%notfound then
                dbms_output.put_line('Employee doesnt exist with deartment id' || i.deptno);
            else
                dbms_output.put_line(i.deptno || ' ' || j.empno || ' ' || j.ename);
            end if;
        end loop;
    end loop;
end;
/

输出:

10 7782 CLARK
10 7839 KING
10 7934 MILLER
20 7369 SMITH
20 7566 JONES
20 7788 SCOTT
20 7876 ADAMS
20 7902 FORD
30 7499 ALLEN
30 7521 WARD
30 7654 MARTIN
30 7698 BLAKE
30 7844 TURNER
30 7900 JAMES

表内容:

SQL> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

SQL> select * from emp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30
      7566 JONES      MANAGER         7839 02-APR-81       2975                    20
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850                    30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10
      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20
      7839 KING       PRESIDENT            17-NOV-81       5000                    10
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30
      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    20

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7900 JAMES      CLERK           7698 03-DEC-81        950                    30
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20
      7934 MILLER     CLERK           7782 23-JAN-82       1300                    10

14 rows selected.

2 个答案:

答案 0 :(得分:1)

您遍历行列表:

BEGIN
    FOR j IN (SELECT * -- fake table with no rows
                FROM DUAL
               WHERE 1 = 2)
    LOOP
        DBMS_OUTPUT.put_line ('work, work..'); -- this won't happen
    END LOOP;
END;

如果没有行,则不会遍历任何内容。

您可以在以下选项中使用sql%notfound

DECLARE
    v_tmp   NUMBER;
BEGIN
    SELECT col1
      INTO v_tmp
      FROM (SELECT 1 col1 FROM DUAL -- select nothing from a fake table
            UNION ALL
            SELECT 2 col1
              FROM DUAL
             WHERE 1 = 2 -- change to 1=1 to get a too-many-rows exception
             );
EXCEPTION
    WHEN OTHERS
    THEN
        IF (SQL%NOTFOUND)
        THEN
            DBMS_OUTPUT.put_line ('I didn''t find anything..');
        ELSE
            DBMS_OUTPUT.put_line ('We have some other exception..');
        END IF;
END;

您的解决方案可能是设置一个标志并在内部循环之后对其进行检查:

DECLARE
    CURSOR c1
    IS
        SELECT * FROM dept;

    CURSOR c2 (p_deptno NUMBER)
    IS
        SELECT *
          FROM emp
         WHERE deptno = p_deptno;

    v_found   BOOLEAN;
BEGIN
    FOR i IN c1
    LOOP
        v_found := FALSE; -- will be set when we find something..

        FOR j IN c2 (i.deptno)
        LOOP
            v_found := TRUE; -- we found something!

            DBMS_OUTPUT.put_line (
                i.deptno || ' ' || j.empno || ' ' || j.ename);
        END LOOP;

        IF (NOT v_found) -- check if we did find i.deptno
        THEN
            DBMS_OUTPUT.put_line (
                'Employee doesnt exist with deartment id' || i.deptno);
        END IF;
    END LOOP;
END;

答案 1 :(得分:0)

如果可以避免的话,请勿在另一个游标中循环。这样,您就重新发明了嵌套循环联接,这可能不是联接结果集的最有效方法。

相反,您应该首先将两个光标合并为一个。这样,优化器就可以选择执行联接的最佳方法。

在您的情况下,您需要将第二个游标与第一个游标进行外部连接,这意味着您的过程将变为:

BEGIN
  FOR i IN (SELECT d.deptno,
                   e.empno,
                   e.ename
            FROM   dept d
            LEFT   OUTER JOIN emp e
            ON     d.deptno = e.deptno)
  LOOP
    IF e.empno IS NOT NULL
    THEN
      dbms_output.put_line('Employee doesn''t exist with department id' || i.deptno);
    ELSE
      dbms_output.put_line(i.deptno || ' ' || i.empno || ' ' || i.ename);
    END IF;
  END LOOP;
END;
/