微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

oracle函数中的多光标

如何解决oracle函数中的多光标

我想创建一个 oracle 函数,该函数将 user_id 作为参数并返回 varchar2,其中包含用户从图书馆拿走但没有归还的书籍的电子邮件文本,我想要的电子邮件文本是: “你好 ” 你应该归还这本书: 1 拍摄于 2. ....

这是我目前写的

create or replace function get_un_recived_books(param_client_id in number) return varchar2 is
  Result varchar2(2000);
 

      
   cursor cur_book is 
      select * from hashala natural join client natural join all_books natural join book
           where 
                    recived =0
                    and recived_date is null
                    and clientid= param_client_id          
                    and taken_date <   add_months(trunc(sysdate,'month'),-3);
                    
        begin
               FOR b IN cur_book LOOP

        Result:= 'book  ' || b.book_name;
  END LOOP;
 
                  
  return(Result);
end;

我有3个问题

  1. 我怎样才能退回所有的书而不是最后一本(比如 c 中的 +=)

  2. 对于客户端名称是否需要添加一个游标,可以吗?

  3. 如何从原始查询传递值

      select get_un_recived_books(!!!ADD HERE THE CLIENID!!!),clientid from hashala natural join client natural join all_books natural join
    

    书 在哪里 收到 =0 并且 recived_date 为空

                     and taken_date <   add_months(trunc(sysdate,-3);
    

enter image description here

解决方法

我没有你的表,所以我将使用 Scott 的示例模式来说明你可以如何做到这一点。阅读代码中的注释。

功能:

SQL> create or replace function f_test (par_deptno in number)
  2    return varchar2
  3  is
  4    l_dname  dept.dname%type;
  5    retval   varchar2(4000);
  6  begin
  7    -- department name (in your case,client name)
  8    select dname
  9      into l_dname
 10      from dept
 11      where deptno = par_deptno;
 12
 13    -- loop through employees in PAR_DEPTNO (in your case,14    -- books client borrowed)
 15    for cur_r in (select ename,hiredate
 16                  from emp
 17                  where deptno = par_deptno
 18                 )
 19    loop
 20      -- this is what you're missing: "retval := retval || ..."
 21      retval := retval || 'Name: ' || cur_r.ename ||
 22               ',borrowed on ' || to_char(cur_r.hiredate,'dd.mm.yyyy') || chr(10);
 23    end loop;
 24
 25    retval := 'Hello,' || l_dname ||chr(10) ||
 26              'you borrowed the following books and didn''t return them yet.' || chr(10) ||
 27              retval;
 28    return retval;
 29  end;
 30  /

Function created.

测试:

SQL> select f_test(10) from dual;

F_TEST(10)
--------------------------------------------------------------------------------
Hello,ACCOUNTING
you borrowed the following books and didn't return them yet.
Name: CLARK,borrowed on 09.06.1981
Name: KING,borrowed on 17.11.1981
Name: MILLER,borrowed on 23.01.1982


SQL>

如果您 - 正如您所说 - 想要“动态”传递 ID,只需将其包含在函数中。类似这样的事情(我正在检索部门 10 和部门 30 的数据,供所有担任文员的人使用):

SQL> select f_test(d.deptno)
  2  from dept d join emp e on e.deptno = d.deptno
  3  where d.deptno in (10,30)
  4    and e.job = 'CLERK';

F_TEST(D.DEPTNO)
------------------------------------------------------------------------
Hello,SALES
you borrowed the following books and didn't return them yet.
Name: ALLEN,borrowed on 20.02.1981
Name: WARD,borrowed on 22.02.1981
Name: MARTIN,borrowed on 28.09.1981
Name: BLAKE,borrowed on 01.05.1981
Name: TURNER,borrowed on 08.09.1981
Name: JAMES,borrowed on 03.12.1981

Hello,borrowed on 23.01.1982


SQL>
,

您可以使用 LISTAGG 函数来实现这一点。这个任务可以通过 view 在纯 SQL 中解决,与函数调用相比,它不会产生子游标。如果您希望选择单个客户,则只需对其进行过滤即可。

但是,如果您愿意,您也可以将相同的文本放入函数中,这也不需要任何循环。因为从 Oracle 12C 及更高版本开始,您可以使用 MAX_STRING_SIZE = EXTENDED 参数将 varchar2 扩展到 32767 字节,与 PL/SQL 相比,这消除了 SQL 中 varchar2 的边界。

两个例子如下:

create table client
as
select
  level as id,'Client ' || level as name
from dual
connect by level < 10
create table book
as
select
  level as id,'Book ' || level as name
from dual
connect by level < 100
create table borrowed_book
as
select
  trunc(level / 4) + 1 as client_id,level as book_id,add_months(sysdate,-mod(level,11)) as dt,case mod(level,4) when 1 then 1 else 0 end as received
from dual
connect by level < 60
create view v_reminder
as
  select
    bb.client_id,c.name as client_name,'Hello,' || max(c.name) || '!'
    || chr(10) || chr(10)
    || 'You should return this books:' || chr(10)
    || listagg(b.name || ' borrowed on ' || to_char(bb.dt,'dd-Mon-yyyy'),chr(10))
         within group(order by bb.dt desc,bb.book_id) as rem

  from borrowed_book bb
    join client c
      on bb.client_id = c.id
    join book b
      on bb.book_id = b.id
  where bb.received = 0
    and bb.dt < add_months(sysdate,-3)
  group by bb.client_id,c.name
create or replace function f_get_reminder(p_client_id in int,p_dt_offset in int default 3)
return varchar2
as
  res varchar2(32000);
begin
  select
    'Hello,bb.book_id)
    
    into res
  from borrowed_book bb
    join client c
      on bb.client_id = c.id
    join book b
      on bb.book_id = b.id
  where bb.received = 0
    and bb.dt < add_months(sysdate,-p_dt_offset)
    and bb.client_id = p_client_id
  /*Added this line to get NULL as output,because aggregate function
  without group by always returns a row even for empty input dataset*/
  group by bb.client_id
  ;
    
  return res;
end;
/
select
  c.id,c.name,f_get_reminder(c.id) as rem
from client c
ID NAME REM
1 客户端 1 null
2 客户端 2 您好,客户 2!

您应该归还这本书:
书 4 借于 2021 年 2 月 27 日
书2020年12月27日借出6册
2020年11月27日借阅7册
3 客户端 3 您好,客户 3!

您应该归还这本书:
2020 年 10 月 27 日借的书 8
Book 2020 年 8 月 27 日借了 10 个
4 客户端 4 您好,客户 4!

您应该归还这本书:
2021 年 2 月 27 日借的第 15 本书
5 客户端 5 您好,客户 5!

您应该归还这本书:
2021 年 1 月 27 日借的第 16 本书
预订2020年11月27日借出18本
2020年10月27日借出19本
6 客户端 6 您好,客户 6!

您应该归还这本书:
2020 年 9 月 27 日借的第 20 本书
7 客户端 7 您好,客户 7!

您应该归还这本书:
2021 年 2 月 27 日借的书 26
Book 2021 年 1 月 27 日借入的 27 个
8 客户端 8 您好,客户 8!

您应该归还这本书:
2020 年 12 月 27 日借的第 28 本书
Book 2020 年 10 月 27 日借出 30 个
2020 年 9 月 27 日借出 31 个
9 客户端 9 您好,客户 9!

您应该归还这本书:
2020 年 8 月 27 日借的第 32 本书

dbfiddle here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。