在PL / SQL中,我可以使用这样的技巧来查找REF CURSOR
中每行的每个列的名称/值对:
TO_CHAR of an Oracle PL/SQL TABLE type
这是一个很棒的技巧。但是当REF CURSOR
为空时它不起作用,例如这里的那个(这只是一个例子。真正的光标不从DUAL
中选择):
OPEN cursor FOR SELECT 1 FROM DUAL WHERE 1 = 0;
空REF CURSOR
是否还有列名/类型信息?
答案 0 :(得分:2)
AFAIK,无法直接从PL / SQL从REF CURSOR
获取元数据。奇怪的是,REF CURSOR
映射到Java ResultSet
,可以查询调用其ResultSet.getMetaData
方法的元数据。
因此,您可以生成Java的存储过程来为您执行此操作。 Here你可以找到一个例子。
另一个选项是使用DBMS_SQL.TO_CURSOR_NUMBER
(仅限11g)将光标转换为数字光标,可以通过DBMS_SQL包询问元数据。
答案 1 :(得分:2)
是的,我尝试过没有行的解决方案,你说得对。 从我有限的观点来看,我认为我们需要两种不同的方法来检索列的名称和值。
1)Dbms_sql包检索列的名称。
2) tbone 方法检索数据。
<强>程序强>
create or replace procedure demo(sqlText in varchar2) is
refCur sys_refcursor;
curId integer;
cnt number;
ret dbms_sql.desc_tab;
recTab dbms_sql.desc_tab;
FORMAT_STRING constant pls_integer := 20;
procedure printDescTab(desctab in sys.dbms_sql.desc_tab) is
begin
-- do what you want with the columns
for i in 1 .. desctab.count
loop
dbms_output.put(lpad(desctab(i).col_name, FORMAT_STRING));
end loop;
dbms_output.new_line;
end printDescTab;
procedure PrintCur(cv in sys_refcursor) is
begin
for c in ( --select t2.COLUMN_VALUE.getrootelement() name,
select EXTRACTVALUE(t2.COLUMN_VALUE, 'node()') value
from table(XMLSEQUENCE(cv)) t
,table(XMLSEQUENCE(EXTRACT(COLUMN_VALUE, '/ROW/node()'))) t2)
loop
DBMS_OUTPUT.put(lpad(c.VALUE, FORMAT_STRING));
end loop;
dbms_output.new_line;
dbms_output.new_line;
end;
begin
dbms_output.put_line('dynamic sql: ' || sqlText);
curId := dbms_sql.open_cursor();
-- checks for sql injection to do...
dbms_sql.parse(curId, sqlText, dbms_sql.native);
dbms_sql.describe_columns(curId, cnt, recTab);
printDescTab(recTab);
dbms_sql.close_cursor(curId);
open refCur for sqlText;
PrintCur(refCur);
close refCur;
exception
when others then
if dbms_sql.is_open(curId) then
dbms_sql.close_cursor(curId);
end if;
if refCur%isopen then
close RefCur;
end if;
dbms_output.put_line(sqlcode || ' - ' || sqlerrm);
end demo;
<强>测试强>
declare
sqlText varchar2(2000);
begin
sqlText := 'select 1 as one, 2 as two from dual where 1=0';
demo(sqlText);
sqlText := 'select name, type || chr(13) type' -- chr(13) specific ASCII Carriage return
||' from user_plsql_object_settings'
||' where name not like ''%$%'' and rownum <= 10';
demo(sqlText);
sqlText := 'select 1 as one, 2 as two from dual ';
demo(sqlText);
exception
when others then
dbms_output.put_line(sqlcode || ' - ' || sqlerrm);
end;
<强>结果强>
dynamic sql: select 1 as one, 2 as two from dual where 1=0
ONE TWO
dynamic sql: select name, type || chr(13) type from user_plsql_object_settings where name not like '%$%' and rownum <= 10
NAME TYPE
ADD_JOB_HISTORY PROCEDURE
AFT_INS_TEST_TRG TRIGGER
BEF_DEL_TEST_TRG TRIGGER
BEF_INS_TEST_TRG TRIGGER
BETWNSTR FUNCTION
BOOL FUNCTION
CACHED_FIBONACCI FUNCTION
DEBUG PACKAGE
DEBUG PACKAGE BODY
DEBUG_TEST PROCEDURE
dynamic sql: select 1 as one, 2 as two from dual
ONE TWO
1 2