oracle 如何在pl/sql中另一个游标的select语句中使用游标中的变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4072992/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 02:51:59  来源:igfitidea点击:

How to use a variable from a cursor in the select statement of another cursor in pl/sql

oracleplsql

提问by VT_programmerWanneBe

I want to run a query, get the results and then iterate through the results of that query with another select statement using the values of the first statement in my 2nd statement (cursor).

我想运行一个查询,获取结果,然后使用我的第二个语句(游标)中的第一个语句的值,使用另一个 select 语句迭代该查询的结果。

I have 40 users in my db. All the users have the same db schema structure. I want to get the username via :

我的数据库中有 40 个用户。所有用户都具有相同的数据库架构结构。我想通过以下方式获取用户名:

SELECT  distinct username 
   from all_users 

then use the user name to run a query like this:

然后使用用户名运行如下查询:

Select lastname, firstname, email, email2 from username.member.

My results set will return multiple rows so I need a row type as well.

我的结果集将返回多行,所以我也需要一个行类型。

I have tried many different pl/sql combinations:

我尝试了许多不同的 pl/sql 组合:

DECLARE
   CURSOR client_cur IS
   SELECT  distinct username 
   from all_users 
   where length(username) = 3;
   -- client cursor 
   CURSOR emails_cur (cli all_users.username%TYPE) IS
   SELECT id, name 
     FROM cli.org;
BEGIN
   FOR client IN client_cur LOOP
      dbms_output.put_line('Client is '|| client.username);
      FOR email_rec in client_cur(client.username) LOOP
         dbms_output.put_line('Org id is ' ||email_rec.id || ' org nam ' || email_rec.name);
      END LOOP;
  END LOOP;
END;
/

and

DECLARE
  CURSOR c1 IS
    SELECT  distinct username from all_users where length(username) = 3;
    client c1%rowtype;
   cursor c2 is Select id, name, allow_digest_flg from c1.username.org;
 digest c2%rowtype;
-- declare record variable that represents a row fetched from the employees table
--   employee_rec c1%ROWTYPE; 
 BEGIN
-- open the explicit cursor and use it to fetch data into employee_rec
    OPEN c1;
  loop
     FETCH c1 INTO client; 
   open c2; 
   loop
    fetch c2 into digest;
      DBMS_OUTPUT.PUT_LINE('digest is : ' || c2.id || ' and name is ' || c2.name || ' flg is ' || c2.allow_digest_flg );
   end loop;
  end loop;
 END;
/

AND MANY VARIATIONS OF THESE.

以及这些的许多变化。

Can someone help me. THANKS

有人能帮我吗。谢谢

回答by Alex Poole

You need to use dynamic SQL to achieve this; something like:

您需要使用动态 SQL 来实现这一点;就像是:

DECLARE
    TYPE cur_type IS REF CURSOR;

    CURSOR client_cur IS
        SELECT DISTING username
        FROM all_users
        WHERE length(username) = 3;

    emails_cur cur_type;
    l_cur_string VARCHAR2(128);
    l_email_id <type>;
    l_name <type>;
BEGIN
    FOR client IN client_cur LOOP
        dbms_output.put_line('Client is '|| client.username);
        l_cur_string := 'SELECT id, name FROM '
            || client.username || '.org';
        OPEN emails_cur FOR l_cur_string;
        LOOP
            FETCH emails_cur INTO l_email_id, l_name;
            EXIT WHEN emails_cur%NOTFOUND;
            dbms_output.put_line('Org id is ' || l_email_id
                || ' org name ' || l_name);
        END LOOP;
        CLOSE emails_cur;
    END LOOP;
END;
/

Editedto correct two errors, and to add links to 10g documentation for OPEN-FORand an example. Editedto make the inner cursor query a string variable.

编辑以更正两个错误,并添加指向 10g 文档OPEN-FOR示例的链接。 编辑以使内部光标查询字符串变量。

回答by Justin Cave

You can certainly do something like

你当然可以做类似的事情

SQL> ed
Wrote file afiedt.buf

  1  begin
  2    for d in (select * from dept)
  3    loop
  4      for e in (select * from emp where deptno=d.deptno)
  5      loop
  6        dbms_output.put_line( 'Employee ' || e.ename ||
  7                              ' in department ' || d.dname );
  8      end loop;
  9    end loop;
 10* end;
SQL> /
Employee CLARK in department ACCOUNTING
Employee KING in department ACCOUNTING
Employee MILLER in department ACCOUNTING
Employee smith in department RESEARCH
Employee JONES in department RESEARCH
Employee SCOTT in department RESEARCH
Employee ADAMS in department RESEARCH
Employee FORD in department RESEARCH
Employee ALLEN in department SALES
Employee WARD in department SALES
Employee MARTIN in department SALES
Employee BLAKE in department SALES
Employee TURNER in department SALES
Employee JAMES in department SALES

PL/SQL procedure successfully completed.

Or something equivalent using explicit cursors.

或者使用显式游标等效的东西。

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor dept_cur
  3        is select *
  4             from dept;
  5    d dept_cur%rowtype;
  6    cursor emp_cur( p_deptno IN dept.deptno%type )
  7        is select *
  8             from emp
  9            where deptno = p_deptno;
 10    e emp_cur%rowtype;
 11  begin
 12    open dept_cur;
 13    loop
 14      fetch dept_cur into d;
 15      exit when dept_cur%notfound;
 16      open emp_cur( d.deptno );
 17      loop
 18        fetch emp_cur into e;
 19        exit when emp_cur%notfound;
 20        dbms_output.put_line( 'Employee ' || e.ename ||
 21                              ' in department ' || d.dname );
 22      end loop;
 23      close emp_cur;
 24    end loop;
 25    close dept_cur;
 26* end;
 27  /
Employee CLARK in department ACCOUNTING
Employee KING in department ACCOUNTING
Employee MILLER in department ACCOUNTING
Employee smith in department RESEARCH
Employee JONES in department RESEARCH
Employee SCOTT in department RESEARCH
Employee ADAMS in department RESEARCH
Employee FORD in department RESEARCH
Employee ALLEN in department SALES
Employee WARD in department SALES
Employee MARTIN in department SALES
Employee BLAKE in department SALES
Employee TURNER in department SALES
Employee JAMES in department SALES

PL/SQL procedure successfully completed.

However, if you find yourself using nested cursor FOR loops, it is almost always more efficient to let the database join the two results for you. After all, relational databases are really, really good at joining. I'm guessing here at what your tables look like and how they relate based on the code you posted but something along the lines of

但是,如果您发现自己使用嵌套游标 FOR 循环,则让数据库为您连接两个结果几乎总是更有效。毕竟,关系数据库真的非常擅长加入。我在这里猜测你的表格是什么样子以及它们是如何根据你发布的代码相关联的,但有些类似

FOR x IN (SELECT *
            FROM all_users,
                 org
           WHERE length(all_users.username) = 3
             AND all_users.username = org.username )
LOOP
  <<do something>>
END LOOP;

回答by René Nyffenegger

Use alter session set current_schema = <username>, in your case as an execute immediate.

alter session set current_schema = <username>在您的情况下使用, 作为立即执行。

See Oracle's documentationfor further information.

有关详细信息,请参阅Oracle 的文档

In your case, that would probably boil down to (untested)

在您的情况下,这可能归结为(未经测试

DECLARE

   CURSOR client_cur IS
     SELECT  distinct username 
       from all_users 
      where length(username) = 3;

   -- client cursor 
   CURSOR emails_cur IS
   SELECT id, name 
     FROM org;

BEGIN

   FOR client IN client_cur LOOP

   -- ****
      execute immediate 
     'alter session set current_schema = ' || client.username;
   -- ****

      FOR email_rec in client_cur LOOP

         dbms_output.put_line(
             'Org id is ' || email_rec.id || 
             ' org nam '  || email_rec.name);

      END LOOP;

  END LOOP;
END;
/