如何解决oracle函数中的多光标
我想创建一个 oracle 函数,该函数将 user_id 作为参数并返回 varchar2,其中包含用户从图书馆拿走但没有归还的书籍的电子邮件文本,我想要的电子邮件文本是:
“你好 ”
你应该归还这本书:
1
这是我目前写的
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个问题
-
我怎样才能退回所有的书而不是最后一本(比如 c 中的 +=)
-
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);
解决方法
我没有你的表,所以我将使用 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 举报,一经查实,本站将立刻删除。