空 Oracle REF CURSOR 中的列名
Posted
技术标签:
【中文标题】空 Oracle REF CURSOR 中的列名【英文标题】:Column names in an empty Oracle REF CURSOR 【发布时间】:2011-07-01 07:29:59 【问题描述】:在 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
是否还有列名/类型信息?
【问题讨论】:
它可能被称为 COLUMN_VALUE。 @Steve:总是?我实际上不是从DUAL
中选择的。这只是一个例子
好的,根据我的经验,未命名的列被命名为 COLUMN_VALUE。不确定这是否适用于您的情况,或者我只是在找错树。
@Lukas,如果游标中没有要处理的行,我不确定您期望从 printCur 过程输出什么信息?你到底是什么意思“它不起作用”?可能我误会你了
@tbone,当我通过 JDBC 执行SELECT 1 AS one FROM DUAL WHERE 1=0
时,我实际上在ResultSet
元数据中得到了列名one
,即使没有行。但从REF CURSOR
获取的ResultSet
并非如此。所以我实际上想知道这是否是 PL/SQL 级别的问题
【参考方案1】:
是的,我已经尝试过没有行的解决方案,你是对的。 从我有限的角度来看,我认为这里我们需要两种不同的方法来检索列的名称和值。
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
【讨论】:
疯了!所以有了 11g,我现在已经为每种类型的光标做好了准备! :) 我只是在想这些小东西,连同视图“user_identifier”(11g)、dbms_application_info 和(一点)努力,可以引导我完成一个很棒的代码检测过程。还是你已经写了? :-) 甜蜜!继续写那个程序! :)【参考方案2】:AFAIK,没有办法直接从 PL/SQL 从REF CURSOR
获取元数据。奇怪的是,REF CURSOR
映射到 Java 的 ResultSet
,可以通过调用 ResultSet.getMetaData
方法来查询元数据。
因此,您可以生成一个 Java 的存储过程来为您执行此操作。 Here你可以找到一个例子。
另一个选项是使用DBMS_SQL.TO_CURSOR_NUMBER
(仅在 11g 中)将光标转换为数字光标,可以通过 DBMS_SQL 包询问元数据。
【讨论】:
我没有提到Java部分,但实际上你不能在空的REF CURSOR
上调用ResultSet.getMetaData
。那会抛出一个异常:-/这就是我问这个问题的最初原因。 +1 猜对了:)
事实证明,一个空的引用光标永远不会被实例化,这就是它不起作用的原因。我不知道,所以谢谢你的警告。似乎您忘记进行单元测试的那种错误:-)
没错!我添加了测试和 bang ! :)以上是关于空 Oracle REF CURSOR 中的列名的主要内容,如果未能解决你的问题,请参考以下文章
让 .NET 了解返回的 REF_CURSOR 中的 Oracle 对象
oracle ref() oracle-00904 无效的列名
使用 JDBC 时,Oracle 的 REF CURSOR 在 Postgresql 中的等价物是啥?
如何在过程中使用返回 Oracle REF_CURSOR 的函数