Dynamic Cursor in plsql (2)

获取cursor行数:

当游标被打开后,%ROWCOUNT归零。第一次提取之前,cursor_name%ROWCOUNT返回0。此后,它返回的fetch到的行数。完成一次fetch操作后,count+1。

获取cursor 列数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
--方法一:
CREATE OR REPLACE FUNCTION count_sql( p_sql IN CLOB )
RETURN INTEGER
AS
        lv_cursor_id    INTEGER;
        lv_columns      DBMS_SQL.DESC_TAB;
        lv_column_count INTEGER;
BEGIN
        -- Open Cursor
        lv_cursor_id := DBMS_SQL.OPEN_CURSOR;
         
        -- Parse Cursor
        DBMS_SQL.PARSE
        ( c             => lv_cursor_id
        , statement     => p_sql
        , language_flag => DBMS_SQL.NATIVE
        );
         
        -- Describe Columns
        DBMS_SQL.DESCRIBE_COLUMNS
        ( c       => lv_cursor_id   
        , col_cnt => lv_column_count
        , desc_t  => lv_columns
        );
         
        -- Close Cursor
        DBMS_SQL.CLOSE_CURSOR(lv_cursor_id);
         
        RETURN lv_column_count;
END count_sql;
/
 
SELECT count_sql('SELECT dummy, dummy, dummy, ''Y'' FROM DUAL') FROM DUAL;
 
COUNT_SQL('SELECTDUMMY,DUMMY,DUMMY,''Y''FROMDUAL')
--------------------------------------------------
                                                 4
================================================================
--方法二:
 
SQL> select column_value cnt from xmltable('count(distinct-values(for $i in ROW/* return name($i)))'
  passing dbms_xmlgen.getxmltype('select ename, sal, hiredate, deptno from emp').extract('ROWSET/ROW')
)
 
CNT 
-----
4   
1 row selected.
SQL> select column_value cnt from xmltable('count(distinct-values(for $i in ROW/* return name($i)))'
  passing dbms_xmlgen.getxmltype('select sal, job, deptno from emp').extract('ROWSET/ROW')
)
 
CNT 
-----
3   
1 row selected.

动态执行sql语句的函数:

func_dynamic_fetch(l_sql);----l_sql 为sql语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
CREATE OR REPLACE TYPE AnydataList FORCE IS VARRAY (2147483647) OF ANYDATA  ;
/
CREATE OR REPLACE TYPE Varchar2List FORCE IS VARRAY (2147483647) OF VARCHAR2 (32767) ;
/
create or replace function func_dynamic_fetch
(   p_sql in varchar2,
    p_no_of_cols integer := 1, 
    p_return_multiple_row boolean := true)
        return anydatalist is
    lc_rs sys_refcursor;
    strlist varchar2List := varchar2List();
    n number := 3;
    code varchar2(32767);
    TYPE ref_cursor IS REF CURSOR;
    rc_         ref_cursor; 
    c_          NUMBER;
    i_          NUMBER;
    col_count_  NUMBER;
    desc_tab_   DBMS_SQL.DESC_TAB2;
    col_num  NUMBER;
    n2 number;
    l_any_list anydatalist;
    l_types varchar2list;
    l_add_stmts varchar2list;
    l_fetch_type varchar2(32767);
    c_date_type constant number := 12;
    c_timestamp_type constant number := 180;
         
 
    function repeatStmt(n in integer, template in varchar2, seperator in varchar2 := '', vals in varchar2list := null) return varchar2 is
        l_result varchar2(32767);
        l_stmt varchar2(32767);
    begin
        for i in 1..n loop
            l_stmt := template;
            if vals is not null then
                l_stmt := replace(template, '__val__', vals(i));
            end if;
            l_result := l_result || replace(l_stmt, '__$__', i);
            if i < n then
                l_result := l_result || seperator;
            end if;
        end loop;
        return l_result;
    end repeatStmt;
begin 
    open rc_ for p_sql; 
    n2 := p_no_of_cols;
    c_ := DBMS_SQL.to_cursor_number(rc_);
    DBMS_SQL.DESCRIBE_COLUMNS2(c_, col_count_, desc_tab_);
    col_num := desc_tab_.first;
    l_types := varchar2list();
    l_add_stmts := varchar2list();
    if col_num is not null then
        loop
            if desc_tab_(col_num).col_type = c_date_type or desc_tab_(col_num).col_type =c_timestamp_type then
                varchar2listAdd(l_types, 'date');
                --to conform to jdbc date format
                varchar2listAdd(l_add_stmts, 'varchar2ListAdd(l_str_list, to_char(a__$__, ''yyyy-mm-dd hh:mi:ss''));');
            else
                varchar2listAdd(l_types, 'varchar2(32767)');
                varchar2listAdd(l_add_stmts, 'varchar2ListAdd(l_str_list, a__$__);');
            end if;
            col_num:= desc_tab_.next(col_num);
            exit when (col_num is null);
        end loop;
    end if;
     
    n := col_count_;
    if n2 > n then
        n2 := n;
    end if;
    dbms_sql.close_cursor(c_);
    code :=
    ' declare
        lc_rs sys_refcursor;
        l_sql varchar2(32767);
        l_str_list varchar2list;
        l_counter integer;
        l_any_list anydatalist; ' || 
        repeatStmt(n, 'a__$__ __val__; ',  seperator => chr(10), vals => l_types) || '
      begin
        l_sql := :0;
        --dbms_output.put_line(l_sql);
        open lc_rs for l_sql;
        l_any_list := anydatalist();
        l_counter := 0;
        loop
            fetch lc_rs into ' || repeatStmt(n, 'a__$__', ', ') || ';' || '
            exit when lc_rs%notfound;
            l_counter := l_counter + 1;
            l_str_list := varchar2List();' ||
            repeatStmt(n2, '__val__', chr(10), vals => l_add_stmts) || '
            anydataListAdd(l_any_list, anydata.convertCollection(l_str_list)); ' ||
            (case when p_return_multiple_row = false then
            'exit when l_counter = 1;'
            end) || '
        end loop;
        if lc_rs%isopen then
            close lc_rs;
        end if;
        :1 := l_any_list;
      exception when others then 
        dbms_output.put_line('' func_dynamic_fetch exec immediate exception: '' || sqlerrm);
        raise;
        if lc_rs%isopen then close lc_rs; end if;
      end;
    ' ;
    execute immediate code using p_sql, out l_any_list;
    return l_any_list;
exception when others then
    if rc_%isopen then close rc_; end if;
    dbms_output.put_line('func_dynamic_fetch: exception: ' || sqlerrm);
    return anydatalist();
end;
 /
show errors;
posted @ 2015-12-18 17:25  MorePrograms  阅读(231)  评论(0编辑  收藏  举报