如何把动态sql的结果集转为XML格式

转载自:http://jackywood.itpub.net/post/1369/161508

在存储过程中, 我们可以用动态sql返回结果集. 动态sql的来源可以是参数, 也可以是存储过程中描述逻辑, 那么如何把动态sql的结果集以XML格式返回呢?



在存储过程中, 我们可以用动态sql返回结果集. 动态sql的来源可以是参数, 也可以是存储过程中描述逻辑, 那么如何把动态sql的结果集以XML格式返回呢?

处理这个问题, 首先先要考虑2个问题:
1. XML格式的数据通过什么方式来转换?
2. 动态sql中的字段名如何获取?

解答:
1. XML格式的数据可以通过Oracle提供的函数xmlelement和xmlattributes来实现
示例如下:


SQL> select * from tb_test;

        ID VAL
---------- ----------------
         1 JGSLQQQY
         2 BLIAELER
         3 WSXAJVHQ
         4 FLTGINNS

4 rows selected.

SQL> select xmlelement("row",
  2          xmlattributes(id as "ID",
  3                        val as "Val"
  4                       )
  5                   ) as val
  6    from tb_test;

VAL
--------------------------------------------------------------------------------
<row ID="1" Val="JGSLQQQY"/>
<row ID="2" Val="BLIAELER"/>
<row ID="3" Val="WSXAJVHQ"/>
<row ID="4" Val="FLTGINNS"/>

4 rows selected.

注意: XML中是大小写敏感的, 因此在选择最后属性节点名称的时候要注意用双引号来, 使字段名大小写敏感.


2. 动态sql中的字段名通过Oracle提供的DBMS_SQL包来实现. (DBMS_SQL的内容在这里不作描述, 详细的参见官方文档.)
示例如下:

  调用DBMS_SQL中的方法, 获取 select * from tb_test 和 select id as "ID", val as "Val" from tb_test 的字段名.
SQL> set serveroutput on
SQL> declare
  2    v_sql varchar2(100);
  3    i_sql integer;
  4    i_col integer;
  5    t_desc dbms_sql.desc_tab;
  6  begin
  7    v_sql := 'select * from tb_test';
  8    i_sql := dbms_sql.open_cursor;
  9    dbms_sql.parse(i_sql, v_sql, dbms_sql.native);
 10    dbms_sql.describe_columns(i_sql, i_col, t_desc);
 11    dbms_output.put_line('The columns of the first SQL:');
 12    for i in 1..i_col loop
 13      dbms_output.put_line(t_desc(i).col_name);
 14    end loop;
 15
 16    v_sql := 'select id as "ID", val as "Val" from tb_test';
 17    i_sql := dbms_sql.open_cursor;
 18    dbms_sql.parse(i_sql, v_sql, dbms_sql.native);
 19    dbms_sql.describe_columns(i_sql, i_col, t_desc);
 20    dbms_output.put_line('The columns of the second SQL:');
 21    for i in 1..i_col loop
 22      dbms_output.put_line(t_desc(i).col_name);
 23    end loop;
 24  end;
 25  /
The columns of the first SQL:
ID
VAL
The columns of the second SQL:
ID
Val

PL/SQL procedure successfully completed.

注意: 两个sql输出的字段名大小写是不同的.


好了, 上述两个问题在技术上解决了, 剩下的就是用存储过程来实现了.


/* 动态sql结果集以XML格式返回, 输入参数就是动态sql, xml的属性节点名的大小写由输入的sql来决定*/
create or replace function func_rec_dynamic(p_sql varchar2) 
return sys_refcursor
as
  v_sql varchar2(4000);
  i_sql integer;
  i_col integer;
  t_desc  dbms_sql.desc_tab;
  c sys_refcursor;
begin
  /* Parse input SQL, and get column names */
  i_sql := dbms_sql.open_cursor;
  dbms_sql.parse(i_sql, p_sql, dbms_sql.native);
  dbms_sql.describe_columns(i_sql, i_col, t_desc);

  /* Obtain dynamic SQL according to parsing input SQL */
  for i in 1..i_col-1 loop
    v_sql := v_sql || '"' || t_desc(i).col_name || '" as "' || t_desc(i).col_name || '",';
  end loop;
  v_sql := v_sql || '"' || t_desc(i_col).col_name || '" as "' || t_desc(i_col).col_name || '"';
  v_sql := 'SELECT xmlelement("row", xmlattributes(' || v_sql ||') ) as val FROM (' || p_sql ||') t';

  /* Execute dynamic SQL to obtain records */
  open c for v_sql;

  return c;
end;
/


func_rec_dynamic函数的使用示例:


SQL> select func_rec_dynamic('select * from tb_test') as col from dual;

COL
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

VAL
--------------------------------------------------------------------------------
<row ID="1" VAL="JGSLQQQY"/>
<row ID="2" VAL="BLIAELER"/>
<row ID="3" VAL="WSXAJVHQ"/>
<row ID="4" VAL="FLTGINNS"/>

4 rows selected.


1 row selected.

SQL> select func_rec_dynamic('select id as "ID", val as "Val" from tb_test') as col from dual;

COL
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

VAL
--------------------------------------------------------------------------------
<row ID="1" Val="JGSLQQQY"/>
<row ID="2" Val="BLIAELER"/>
<row ID="3" Val="WSXAJVHQ"/>
<row ID="4" Val="FLTGINNS"/>

4 rows selected.


1 row selected.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值