1.获取动态SQL中的列名及类型

DECLARE
l_curid INTEGER;
l_cnt NUMBER;
l_desctab dbms_sql.desc_tab;
l_sqltext VARCHAR2(2000);
BEGIN
l_sqltext := 'select *
from dba_objects where rownum<= 10'; --可以是任意有效的查询sql文本
l_curid := dbms_sql.open_cursor();
dbms_sql.parse(l_curid, l_sqltext, dbms_sql.native);
dbms_sql.describe_columns(l_curid, l_cnt, l_desctab);
FOR i IN 1 .. l_desctab.count LOOP
dbms_output.put_line(rpad(l_desctab(i).col_name, 30)||rpad(l_desctab(i).col_type, 3));
END LOOP;
dbms_sql.close_cursor(l_curid);
END;

查询结果

OWNER                         1
OBJECT_NAME 1
SUBOBJECT_NAME 1
OBJECT_ID 2
DATA_OBJECT_ID 2
OBJECT_TYPE 1
CREATED 12
LAST_DDL_TIME 12
TIMESTAMP 1
STATUS 1
TEMPORARY 1
GENERATED 1
SECONDARY 1
NAMESPACE 2
EDITION_NAME 1
SHARING 1
EDITIONABLE 1
ORACLE_MAINTAINED 1
col_type 1:VARCAHR2,2:NUMBER,12:DATE

2.使用USING方式绑定动态SQL,获取列名及对应的值

-- Created on 2017/10/11 by ADMINISTRATOR
DECLARE
TYPE typecursor IS REF CURSOR;
cursrc typecursor;
curid NUMBER;
desctab dbms_sql.desc_tab;
colcnt NUMBER;
vname VARCHAR2(50);
vnum NUMBER;
vdate DATE;
rownumber NUMBER := 5; sqlstmt VARCHAR2(2000);
BEGIN
sqlstmt := 'SELECT * FROM fnd_user WHERE rownum < :rownumber';
-- 打开光标
OPEN cursrc FOR sqlstmt
USING rownumber; -- 从本地动态SQL转换为DBMS_SQL
curid := dbms_sql.to_cursor_number(cursrc);
--获取游标里面的数据列项数和每个数据列的属性,比如列名,类型,长度等
dbms_sql.describe_columns(curid, colcnt, desctab);
-- 定义列
FOR i IN 1 .. colcnt LOOP
--此处是定义游标中列的读取类型,可以定义为字符,数字和日期类型,
IF desctab(i).col_type = 2 THEN
dbms_sql.define_column(curid, i, vnum);
ELSIF desctab(i).col_type = 12 THEN
dbms_sql.define_column(curid, i, vdate);
ELSE
dbms_sql.define_column(curid, i, vname, 50);
END IF;
END LOOP;
-- DBMS_SQL包获取行
--从游标中把数据检索到缓存区(BUFFER)中,缓冲区 的值只能被函数COULUMN_VALUE()所读取
WHILE dbms_sql.fetch_rows(curid) > 0 LOOP
   --函数column_value()把缓冲区的列的值读入相应变量中。
FOR i IN 1 .. colcnt LOOP
IF (desctab(i).col_type = 1) THEN
dbms_sql.column_value(curid, i, vname);
dbms_output.put_line(desctab(i).col_name || ' ' || vname || ', ');
ELSIF (desctab(i).col_type = 2) THEN
dbms_sql.column_value(curid, i, vnum);
dbms_output.put_line(desctab(i).col_name || ' ' || vnum || ', ');
ELSIF (desctab(i).col_type = 12) THEN
dbms_sql.column_value(curid, i, vdate);
dbms_output.put_line(desctab(i).col_name || ' ' ||
to_char(vdate, 'YYYY-MM-DD HH24:MI:SS') || ', ');
END IF;
END LOOP;
END LOOP;
dbms_sql.close_cursor(curid);
END;

3.使用DBMS_SQL.BIND_VARIABLE方式传递参数,获取列名及对应的值

DECLARE
v_cursor NUMBER;
v_stat NUMBER;
v_row NUMBER;
v_id NUMBER;
v_no VARCHAR(100);
v_date DATE;
v_sql VARCHAR(200);
s_id NUMBER;
s_date DATE;
BEGIN
s_id := 1131;
s_date := SYSDATE;
v_sql := 'SELECT fu.user_id, fu.user_name, fu.CREATION_DATE FROM fnd_user fu where fu.user_id = :userId';
v_cursor := dbms_sql.open_cursor; --打开游标;
dbms_sql.parse(v_cursor, v_sql, dbms_sql.native); --解析动态SQL语句;
dbms_sql.bind_variable(v_cursor, ':userId', s_id); --绑定输入参数; dbms_sql.define_column(v_cursor, 1, v_id); --定义列
dbms_sql.define_column(v_cursor, 2, v_no, 100);
dbms_sql.define_column(v_cursor, 3, v_date);
v_stat := dbms_sql.execute(v_cursor); --执行动态SQL语句。
LOOP
EXIT WHEN dbms_sql.fetch_rows(v_cursor) <= 0; --fetch_rows在结果集中移动游标,如果未抵达末尾,返回1。
dbms_sql.column_value(v_cursor, 1, v_id); --将当前行的查询结果写入上面定义的列中。
dbms_sql.column_value(v_cursor, 2, v_no);
dbms_sql.column_value(v_cursor, 3, v_date);
dbms_output.put_line(v_id || ';' || v_no || ';' || v_date);
END LOOP;
dbms_sql.close_cursor(v_cursor); --关闭游标。
END;

参考:

PLSQL Language Referenc-PL/SQL动态SQL-DBMS_SQL包-DBMS_SQL.TO_CURSOR_NUMBER()函数

使用Oracle的DBMS_SQL包执行动态SQL语句

Oracle之DBMS_SQL包用法详解

PLSQL中怎样获取未知结构的动态游标(REF CURSOR)的字段


最后一份来自百度文库的不好复制,现整理如下

  对于使用过 ORACLE PLSQL 中的动态游标的人来说,我相信有不少人都会有这样的想法:如果对于任意一个给定的未知结构的游标(REF CURSOR),我们都能够在PLSQL中获取它的所有字段的名称,那该多好啊!不知道你是否有这样的想法,反正我早就有这样的想法了,也百度了多次,但结果不尽人意。曾经一度以为,这是不可能的。但是PLSQL Developer中的test 窗口中,可以打开任意游标并得到字段名及值。很显然,还是有办法得到未知结构的动态游标的字段名的,只是我不知道方法而已。
  今天早上心血来潮,又想到这个事情,于是google了一下(用英文查询:how to get column names from oracle cursor),发现还真有办法获取未知结构的动态游标!看来在这方面百度还是太弱啊!技术问题还是得问google。
  整理之后,结论如下:

1、如果给的是一个查询SQL文本,那么事情很容易(对于9i及以上版本),只要使用dbms_sql.open_cursor打开游标,再使用dbms_sql.describe_columns即可得到游标的所有字段名称及类型等数据,存储在一个集合类型变量中(具体请看dbms_sql.desc_tab)。请参考如下PLSQL代码:

DECLARE
l_curid INTEGER;
l_cnt NUMBER;
l_desctab dbms_sql.desc_tab;
l_sqltext VARCHAR2(2000);
BEGIN
l_sqltext := 'select *
from dba_objects where rownum<= 10'; --可以是任意有效的查询sql文本
l_curid := dbms_sql.open_cursor();
dbms_sql.parse(l_curid, l_sqltext, dbms_sql.native);
dbms_sql.describe_columns(l_curid, l_cnt, l_desctab);
FOR i IN 1 .. l_desctab.count LOOP
dbms_output.put_line(rpad(l_desctab(i).col_name, 30)||rpad(l_desctab(i).col_type, 3));
END LOOP;
dbms_sql.close_cursor(l_curid);
END;

  注意,必须使用 DBMS_SQL.OPEN_CURSOR 打开游标,否则,就不是这种处理方法了。
  2、如果给的是一个REF CURSOR类型变量,而不知道SQL文本,该怎么办呢?这里分两种情况:
  1) 如果数据库版本是11g及以上,同样很容易:使用dbms_sql.to_cursor_number(cursor) 得到游标的ID,再使用dbms_sql.describe_columns即可得到游标字段名称。参考如
下代码:

DECLARE
TYPE ref_cursor IS REF CURSOR;
l_cursor ref_cursor;
l_curid NUMBER;
l_col_cnt NUMBER;
l_desc_tab dbms_sql.desc_tab;
BEGIN
OPEN l_cursor FOR 'select owner,object_type,object_name from dba_objects where rownum<= 10';
l_curid := dbms_sql.to_cursor_number(l_cursor);
dbms_sql.describe_columns(l_curid, l_col_cnt, l_desc_tab);
FOR i IN 1 .. l_col_cnt LOOP
dbms_output.put_line(l_desc_tab(i).col_name);
END LOOP;
dbms_sql.close_cursor(l_curid);
END;

  2) 如果数据库版本低于11g,则PLSQL中仅有如下方法可以获取字段名称及字段值:

DECLARE
l_cursor SYS_REFCURSOR;
i NUMBER := 0;
CURSOR get_columns IS
SELECT t2.column_value.getrootelement() NAME,
extractvalue(t2.column_value, 'node()') VALUE
FROM (SELECT * FROM TABLE(xmlsequence(l_cursor))) t1,
TABLE(xmlsequence(extract(t1.column_value, '/ROW/node()'))) t2;
BEGIN
OPEN l_cursor FOR 'select owner,object_type,object_name from dba_objects where rownum<= 10';
FOR rec_ IN get_columns LOOP
i := i + 1;
dbms_output.put_line(rpad(i,2) || ':' || rpad(rec_.name,15) || ': ' || lpad(rec_.value,15));
END LOOP;
CLOSE l_cursor;
END;

  用这种方法,可以得到动态游标的所有数据,包括字段名称和字段值。但这种方法会遍历游标,即游标已经走到底了,不能再次使用了。而使用dbms_sql.describe_columns不会对游标的光标位置产生任何影响。两者优劣一目了然。
  对于JAVA、C等外部编程语言而言,要从游标中获取字段名称是比较容易的。可以用JAVA语言写一个获取游标字段名称的存储过程,并编译至数据库中,且做成PLSQL接口,这样就可以在PLSQL中调用了。有意者可以自己去研究下,或者向精通JAVA者请教。

ORACLE中使用DBMS_SQL获取动态SQL执行结果中的列名和值的更多相关文章

  1. ORACLE动态sql在存储过程中出现表或视图不存在的解决方法

    Oracle动态sql在存储过程中出现表或视图不存在的解决方法 CREATE OR REPLACE PROCEDURE P_test is strsql varchar2(2000); BEGIN   ...

  2. PL/SQL --> 动态SQL调用包中函数或过程

    动态SQL主要是用于针对不同的条件或查询任务来生成不同的SQL语句.最常用的方法是直接使用EXECUTE IMMEDIATE来执行动态SQL语句字符串或字符串变量.但是对于系统自定义的包或用户自定的包 ...

  3. 获取动态SQL查询语句返回值(sp_executesql)

    在写存储过程时经常会遇到需要拼接SQL语句的情况,一般情况下仅仅是为了执行拼接后的语句使用exec(@sql)即可. 而今天的一个存储过程却需要获取动态SQL的查询结果. 需求描述:在某表中根据Id值 ...

  4. mysql 5.7.20 取得动态sql执行结果

    drop procedure test; delimiter ;; CREATE procedure test() -- 取动态sql的值 begin ); ); set v_sqlcounts = ...

  5. SQL执行过程中的性能负载点

    一.SQL执行过程 1.用户连接数据库,执行SQL语句: 2.先在内存进行内存读,找到了所需数据就直接交给用户工作空间: 3.内存读失败,也就说在内存中没找到支持SQL所需数据,就进行物理读,也就是到 ...

  6. Mybatis中输入输出映射和动态Sql

    一.输入映射 我们通过配置parameterType的值来指定输入参数的类型,这些类型可以是简单数据类型.POJO.HashMap等数据类型 1.简单类型 2.POJO包装类型 ①这是单表查询的时候传 ...

  7. 在PL/SQL中使用游标、动态sql和绑定变量的小例子

    需求:查询并输出30号部门的雇员信息 方式一:使用 loop...fetch SET serveroutput ON; DECLARE CURSOR c_emp IS ; v_emp emp%rowt ...

  8. sqlserver 动态sql执行execute和sp_executesql

    sp_executesql的运用 书写语法要点: exec sp_executesql @sql,N’参数1 类型1,参数2 类型2,参数3 类型3 OUTPUT’,参数1,参数2,参数3 OUTPU ...

  9. sqlserver中sp_executesql使用实例(获取动态sql输出结果)

    语法 sp_executesql [ @stmt = ] stmt [     {, [@params=] N'@parameter_name data_type [ [ OUT [ PUT ][,. ...

随机推荐

  1. P3627 [APIO2009]抢掠计划

    P3627 [APIO2009]抢掠计划 Tarjan缩点+最短(最长)路 显然的缩点...... 在缩点时,顺便维护每个强连通分量的总权值 缩完点按照惯例建个新图 然后跑一遍spfa最长路,枚举每个 ...

  2. c++标准库多线程入门

    从c++ 11开始,语言核心和标准库开始引入了对多线程的原生支持.如下所示: int doSth(char c) { default_random_engine dre(c); uniform_int ...

  3. 基于Android应用《玩转英语》(总报告)

                                                                         基于Android应用<玩转英语>   摘  要 ...

  4. 上周日选拔题部分write up

    ---恢复内容开始--- 第一题.平淡无奇的签到题,“百度一下,你就知道”,打开之后会弹出一个百度的网页页面.网页题第一步,先查看它的源代码.从上往下看,发现了这样一行字 看起来有点像base编码,于 ...

  5. poj 1274 The Perfect Stal - 网络流

    二分匹配传送门[here] 原题传送门[here] 题意大概说一下,就是有N头牛和M个牛棚,每头牛愿意住在一些牛棚,求最大能够满足多少头牛的要求. 很明显就是一道裸裸的二分图最大匹配,但是为了练练网络 ...

  6. FTP-IIS Web

    快速搭建一个本地的FTP服务器   如果需要开发FTP文件上传下载功能,那么需要在本机上搭建一个本地FTP服务器,方便调试. 第一步:配置IIS Web服务器 1.1 控制面板中找到“程序”并打开 1 ...

  7. Git 基础笔记整理1

    Git 官网:http://git-scm.com/ git教程1:http://www.yiibai.com/git/home.html git教程2 :http://www.liaoxuefeng ...

  8. sql逻辑查询语句的执行顺序

    SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOIN ...

  9. [Java] - MySQL数据库的时间设置问题.

    之前有朋友做的项目时间格式设置为String,我感觉很不好,随后自己试了试. 首先在设置数据库类型时,选择的是timestamp, 而Java的实体中设置时间的属性类型为Date, (java.uti ...

  10. java多线程编程模式

    前言 区别于java设计模式,下面介绍的是在多线程场景下,如何设计出合理的思路. 不可变对象模式 场景 1. 对象的变化频率不高 每一次变化就是一次深拷贝,会影响cpu以及gc,如果频繁操作会影响性能 ...