【发布时间】:2018-07-20 15:36:23
【问题描述】:
一些背景:我正在考虑以某种方式创建一个 apex 插件,非常具体但可在同一个项目中重复使用。我只是通过研究我的选择来解决这个问题。我真的不需要它,因为 refcursor 将满足我的需求,因为我总是期望一个具有相同列名和数据类型的语句。问题是查询可以在不同的数据集上执行(想想带有定义的表和带有用户数据的表)。
所以我在想:如果尝试更动态地处理这个问题呢?
游标语句将允许我只要求用户在界面提供的一个语句框中编写他的查询(如果您知道 apex,区域源 sql),而不会将事情拆分或使其复杂化。但我对如何处理这个问题有点困惑。似乎根本没有任何方法可以解决这个问题。例如,使用以下语句可以描述查询并确定列是否为 CURSOR 类型。但它停在那里。没有办法抓住这个实际的光标并用它做点什么。
一些测试表+数据DDL
create table test_a (id number, title varchar2(200))
create table test_b (id number, a_id number, title varchar2(200));
create table test_c (id number, b_id number, title varchar2(200));
insert into test_a (id, title) values (1, 'hoofd 1');
insert into test_a (id, title) values (2, 'hoofd 2');
insert into test_b (id, a_id, title) values (1, 1, 'h1 - child 1');
insert into test_b (id, a_id, title) values (2, 1, 'h1 - child 2');
insert into test_b (id, a_id, title) values (3, 2, 'h2 - child 1');
insert into test_b (id, a_id, title) values (4, 2, 'h2 - child 2');
insert into test_c (id, b_id, title) values (1, 1, 'h1 - c1 - A');
insert into test_c (id, b_id, title) values (2, 2, 'h1 - c2 - B');
insert into test_c (id, b_id, title) values (3, 3, 'h2 - c1 - C');
insert into test_c (id, b_id, title) values (4, 4, 'h2 - c2 - D');
清理一下:
drop table test_a;
drop table test_b;
drop table test_c;
就像,我理解为什么以下工作,但正如您所见,它需要了解光标的内容并且代码应该处理它。
declare
l_stmt varchar2(32000);
l_c sys_refcursor;
l_vc varchar2(4000);
l_sub sys_refcursor;
procedure children (p_c in sys_refcursor)
is
l_k varchar2(200);
l_c sys_refcursor;
begin
loop
fetch p_c into l_k, l_c;
exit when p_c%NOTFOUND;
dbms_output.put_line('L2 titel: '||l_k);
end loop;
end;
begin
l_stmt := q'[select title
, cursor(
select title, cursor(
select title
from test_c
where b_id = b.id
)
from test_b b
where a_id = a.id
)
from test_a a]';
open l_c for l_stmt;
loop
fetch l_c into l_vc, l_sub;
exit when l_c%NOTFOUND;
dbms_output.put_line('L1 titel: '||l_vc);
children(l_sub);
end loop;
close l_c;
end;
/
以下带有 DBMS_SQL 的代码失败。当然。接受 CURSOR 类型作为 DBMS_SQL 中的类型没有重载。
set serveroutput on
declare
l_stmt VARCHAR2(32000);
l_cur_id BINARY_INTEGER;
l_rows INTEGER;
l_desctab DBMS_SQL.DESC_TAB3;
l_colcnt NUMBER;
l_count BINARY_INTEGER := 0;
l_varchar VARCHAR2(4000);
l_sub SYS_REFCURSOR;
begin
l_stmt := q'[select title
, cursor(
select title, cursor(
select title
from test_c
where b_id = b.id
)
from test_b b
where a_id = a.id
)
from test_a a]';
l_cur_id := dbms_sql.open_cursor;
dbms_sql.parse(l_cur_id, l_stmt, dbms_sql.native);
dbms_sql.describe_columns3(l_cur_id, l_colcnt, l_desctab);
FOR i IN 1 .. l_colcnt LOOP
dbms_output.put_line('col '||i||' type: '||l_desctab(i).col_type);
END LOOP;
-- describing it works, and would return type id 102, which I suppose is CURSOR.
dbms_sql.define_column(l_cur_id, 1, l_varchar, 4000);
dbms_sql.define_column(l_cur_id, 2, l_sub); --> fails, evidently
--l_rows := dbms_sql.execute(l_cur_id);
dbms_sql.close_cursor(l_cur_id);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('error: '||sqlerrm);
dbms_sql.close_cursor(l_cur_id);
END;
/
如果没有办法,那也没关系。在学术上,我只是想知道。也许还有其他方法可以做到这一点。也许我错过了一些东西。我在想,也许可以组装 plsql 代码并动态执行它,但这听起来很重要。就像通过查找游标语句手动解析语句一样,我不会参与。
顺便说一句,在 sqldeveloper 中执行查询工作正常,它会显示以下内容:
hoofd 1 {<TITLE=h1 - child 1,CURSOR(SELECTTITLE={<TITLE=h1 - c1 - A>,}>,<TITLE=h1 - child 2,CURSOR(SELECTTITLE={<TITLE=h1 - c2 - B>,}>,}
hoofd 2 {<TITLE=h2 - child 1,CURSOR(SELECTTITLE={<TITLE=h2 - c1 - C>,}>,<TITLE=h2 - child 2,CURSOR(SELECTTITLE={<TITLE=h2 - c2 - D>,}>,}
当然,这可能完全出于其他原因。
【问题讨论】: